Java 如何在多线程环境中使生成器模式线程安全?

Java 如何在多线程环境中使生成器模式线程安全?,java,multithreading,thread-safety,builder,Java,Multithreading,Thread Safety,Builder,我正在从事一个项目,在这个项目中,我需要java客户机的同步和异步方法。一些客户将调用我的java客户机的同步方法,一些客户将根据需要调用异步方法 下面是我的java客户端,它有同步和异步方法- public class TestingClient implements IClient { private ExecutorService service = Executors.newFixedThreadPool(10); private RestTemplate restTe

我正在从事一个项目,在这个项目中,我需要java客户机的同步和异步方法。一些客户将调用我的java客户机的同步方法,一些客户将根据需要调用异步方法

下面是我的java客户端,它有
同步
异步
方法-

public class TestingClient implements IClient {

    private ExecutorService service = Executors.newFixedThreadPool(10);
    private RestTemplate restTemplate = new RestTemplate();

    // for synchronous
    @Override
    public String executeSync(ClientKey keys) {

        String response = null;
        try {

            Future<String> handle = executeAsync(keys);
            response = handle.get(keys.getTimeout(), TimeUnit.MILLISECONDS);
        } catch (TimeoutException e) {

        } catch (Exception e) {

        }

        return response;
    }

    // for asynchronous
    @Override
    public Future<String> executeAsync(ClientKey keys) {

        Future<String> future = null;

        try {
            ClientTask ClientTask = new ClientTask(keys, restTemplate);
            future = service.submit(ClientTask);
        } catch (Exception ex) {

        }

        return future;
    }
}
下面是我的
ClientKey
类,它使用Builder模式,客户将使用该模式将输入参数传递给
TestingClient
-

public final class ClientKey {

    private final long userId;
    private final int clientId;
    private final long timeout;
    private final boolean testFlag;
    private final Map<String, String> parameterMap;

    private ClientKey(Builder builder) {
    this.userId = builder.userId;
    this.clientId = builder.clientId;
    this.remoteFlag = builder.remoteFlag;
    this.testFlag = builder.testFlag;
    this.parameterMap = builder.parameterMap;
    this.timeout = builder.timeout;
    }

    public static class Builder {
    protected final long userId;
    protected final int clientId;
    protected long timeout = 200L;
    protected boolean remoteFlag = false;
    protected boolean testFlag = true;
    protected Map<String, String> parameterMap;

    public Builder(long userId, int clientId) {
        this.userId = userId;
        this.clientId = clientId;
    }

    public Builder parameterMap(Map<String, String> parameterMap) {
        this.parameterMap = parameterMap;
        return this;
    }

    public Builder remoteFlag(boolean remoteFlag) {
        this.remoteFlag = remoteFlag;
        return this;
    }

    public Builder testFlag(boolean testFlag) {
        this.testFlag = testFlag;
        return this;
    }

    public Builder addTimeout(long timeout) {
        this.timeout = timeout;
        return this;
    }

    public ClientKey build() {
        return new ClientKey(this);
    }
    }

    public long getUserId() {
    return userId;
    }

    public int getClientId() {
    return clientId;
    }

    public long getTimeout() {
    return timeout;
    }

    public Map<String, String> getParameterMap() {
    return parameterMap;

    public boolean istestFlag() {
    return testFlag;
    }
}
因此,请尝试了解我上面的代码是否是线程安全的,因为它们可以从多个线程向我的
TestingClient
类传递多个值。我感觉我的
ClientKey
类不是线程安全的,因为
parameterMap
但不确定

我也需要
StringBuffer
这里还是
StringBuilder
就可以了,因为StringBuilder比StringBuffer快,因为它不同步。


有人能帮我吗?

参数
ClientKey-keys
是给定的,所以我假设总是不同的

我认为您的代码没有任何同步问题,我将解释:

ClientTask ClientTask = new ClientTask(keys, restTemplate);
future = service.submit(ClientTask);
  • 从方法内部创建一个
    ClientTask
    对象,该对象不在线程之间共享
  • 使用
    service.submit
    ,返回未来的对象
  • ClientTask
    对象只读取方法
    generateURL
    中的键,但是,正如我前面所说的,
    ClientKeys
    对象是作为一个参数给出的,所以只要不共享这个对象,就可以了
总之,代码的线程安全性取决于
ExecutorService
Future
是否是线程安全的

更新:只要未共享此对象,
的说明

ClientKeys keys;
add keys to @keys
.. code
executeAsync(.., keys)
... code
add keys to @keys
add keys to @keys
executeAsync(.., keys)
executeAsync(.., keys)
add keys to @keys
... code
add keys to @keys
executeAsync(.., keys)
这是(越来越少)我的意思是分享<由于调用executeAsync(),代码>键
正在多个线程中使用。在这种情况下,一些线程正在读取
,而另一些线程正在
向其中写入数据,这导致了通常称为


更新2:
StringBuffer
对象是本地对象(aka在
generateURL
的范围内),不需要对其进行同步。

如果要确保在分配给ClientKey后无法修改parameterMap,需要执行以下操作:
this.parameterMap=Collections.unmodifiableMap(新HashMap(建筑商参数地图)
但是,如果当前有多个线程正在访问一个未同步的LinkedHashMap,则您的ClientKey外部代码中已经有问题。感谢Erwin的建议。客户可以将不同线程中的不同值传递给
TestingClient
类,这意味着他们需要使用
ClientKey
类进行输入参数always as userId会在每次调用时不断更改,ParameterMap也会更改。
LinkedHashMap
code就是一个示例,客户会从那里调用我们的应用程序。他们可以在那里使用ConcurrentHashMap,因为它会为他们如何调用我们编码。。感谢ichramm的建议n、 只要这个对象没有被共享,当人们说
时,我总是感到困惑。
这实际上意味着什么?因为每次调用的Clientkey键都会不同。所以在我的场景中,你看到这会发生吗?根据你写的关于你客户的内容和最后一个代码块,不,我认为不会发生。我明白了。还有我在这里需要StringBuffer吗?或者StringBuilder在我的
generateURL
方法中也可以,因为StringBuilder比StringBuffer快,因为它不同步。
StringBuffer
对象是本地对象(aka在
generateURL
的范围内),不需要同步它。
ClientTask ClientTask = new ClientTask(keys, restTemplate);
future = service.submit(ClientTask);
ClientKeys keys;
add keys to @keys
.. code
executeAsync(.., keys)
... code
add keys to @keys
add keys to @keys
executeAsync(.., keys)
executeAsync(.., keys)
add keys to @keys
... code
add keys to @keys
executeAsync(.., keys)