线程使用的System.setProperty会影响与外部网络元素通信的其他线程.怎么解决?

Har*_*ari 3 java sockets

在我的应用程序中,我有两个线程.每个线程与不同的外部实体通信.

让我们说T1 - > N1和T2 - > N2(T1和T2是两个线程.N1和N2是外部实体.通信是基于HTTPS的SOAP.)

N1的供应商要求使用密钥存储文件UPCC_client.store进行身份验证,同样我们使用了以下代码,

System.setProperty("javax.net.ssl.keyStore", "<file path>");
System.setProperty("javax.net.ssl.keyStorePassword", "<password>");
System.setProperty("javax.net.ssl.trustStore","<file path>");
System.setProperty("javax.net.ssl.trustStorePassword", "<password>");
Run Code Online (Sandbox Code Playgroud)

已使用T1线程中设置的上述属性重新启动应用程序,没有任何问题.T2开始遇到麻烦,因为T1设置的属性被T2使用.这背后的主要原因System.setProperty是JVM范围.如何解决这个问题?

Pet*_*rey 16

我怀疑你有一个设计问题,但有这个要求.

解决这个问题的唯一方法是我能想到的是使你的属性成为ThreadLocal.

public class ThreadLocalProperties extends Properties {
    private final ThreadLocal<Properties> localProperties = new ThreadLocal<Properties>() {
        @Override
        protected Properties initialValue() {
            return new Properties();
        }
    };

    public ThreadLocalProperties(Properties properties) {
        super(properties);
    }

    @Override
    public String getProperty(String key) {
        String localValue = localProperties.get().getProperty(key);
        return localValue == null ? super.getProperty(key) : localValue;
    }

    @Override
    public Object setProperty(String key, String value) {
        return localProperties.get().setProperty(key, value);
    }
}

// Make the properties thread local from here. This to be done globally once.
System.setProperties(new ThreadLocalProperties(System.getProperties()));

// in each thread.
System.setProperty("javax.net.ssl.keyStore", "my-key-store");
Run Code Online (Sandbox Code Playgroud)

除非有任何混淆,否则System.setProperties()不仅会设置属性,而是替换集合及其实现.

// From java.lang.System
 * The argument becomes the current set of system properties for use
 * by the {@link #getProperty(String)} method.

public static void setProperties(Properties props) {
    SecurityManager sm = getSecurityManager();
    if (sm != null) {
        sm.checkPropertiesAccess();
    }
    if (props == null) {
        props = new Properties();
        initProperties(props);
    }
    System.props = props;
}
Run Code Online (Sandbox Code Playgroud)

通过使用此方法,系统属性的行为更改为调用setProperty()和getProperty()的线程本地

  • @Hari 这是系统属性的默认行为。上面的解决方案更改了默认行为,因此设置属性是线程本地的。即,如果您更改一个线程中的值,则不会更改另一个线程中的值。 (2认同)

小智 5

我来到这里寻找一个解决方案来设置每个线程的系统属性。我在上面使用了 @Peter Lawrey 的优秀示例,这正是我所需要的,但有一个例外 - 我的代码需要在 servlet 容器(Tomcat)内运行,因此我有义务成为一名好公民,而不是改变预期的行为对于在同一 JVM 实例中运行的任何其他 Web 应用程序,可以使用 setProperty() 方法。为了解决这个问题,我将 Peter 的setProperty()方法重命名为setLocalProperty()

    public Object setThreadLocalProperty(String key, String value) {
        return localProperties.get().setProperty(key, value);
    }
Run Code Online (Sandbox Code Playgroud)

通过这一更改,结果是对 setProperty() 的调用将全局更改该属性 - 这将是 JVM 中其他线程所需的行为。要仅更改本地线程的属性,请改为调用setThreadLocalProperty().

总之,如果您可以完全控制您的应用程序实例,那么 Peter 的代码应该非常适合您。然而,如果您的应用程序位于共享 JVM 中,或者您需要将系统属性“分层”到全局和线程本地,则上述一项修改应该适合您。