如何使静态成员和函数线程安全?

时间:2017-07-02 12:54:39

标签: java multithreading

我有一个定义为:

的类
class Artifacts {
    private static boolean isThreadStarted = false;
    private SomeClass someClass;
    public static void startThread() {
        isThreadStarted = true;
    }
    public static void setSomeClass(SomeClass = someClass1) {
       if(isThreadStarted) {
           someClass = someClass1;
       }
    }
    public static SomeClass getSomeClass() {
        return someClass;
    }
}

现在的用例是一个方法将isThreadStarted的值设为true。之后,一个线程将启动并使用someClass的值。可以设置多个线程并获取someClass的值。我想让这个线程安全。

有一个注释@ThreadSafe并且有一个函数synchronized static,我想这会做的事情。请帮助决定正确的方法。

3 个答案:

答案 0 :(得分:1)

为了使这个类更符合预期目的,可以进行两个简单的改进,使someClass字段变为volatile,并将isomicBoolean用于i​​sThreadStarted字段。

class Artifacts {
    private static AtomicBoolean isThreadStarted = new AtomicBoolean(false);
    private volatile SomeClass someClass;

volatile将确保任何其他具有Artifact实例引用的线程都不会缓存someClass实例。 JVM将始终从一个主源检索someClass字段。如果没有使用volatile,那么其他线程可能会缓存someClass并更改它,它可能不会反映在使用它的所有线程上。

AtomicBoolean为您提供易失性功能和原子操作,例如在同一操作中检查和设置。以下是Javadoc的摘录。

  

一个小型工具包,支持对单个变量进行无锁线程安全编程。本质上,此包中的类将volatile值,字段和数组元素的概念扩展为也提供表单的原子条件更新操作的那些:

答案 1 :(得分:1)

因此,您主要担心的是多个线程会读取和写入someClass字段(也可能是isThreadStarted字段)。

我不知道@ThreadSafe注释的作用,它不是Java Standard Edition 8的一部分。

使线程安全的基本方法是使用synchronized关键字。通常,您可以在getter和setter方法中封装对字段的访问,并使它们同步。

public class Test {
    private String someText;
    public synchronized String getSomeText() {
        return someText;
    }
    public synchronized void setSomeText(String someText) {
        this.someText = someText;
    }
}

但通常多线程问题不依赖于单个字段。

如果程序的不同线程使用(线程共享)对象,则会遇到一个线程修改两个字段A和B的风险(例如,通过从A中减去并添加到B,将资金从A移到B),并且在其他一些线程读取A和B之间(例如计算A加B的当前数量)并看到一个不一致的状态(从A减去但尚未加到B的数量)。

经典的解决方案是确保在读取或修改实例的所有这些代码段中,只允许一次运行一个代码段。这就是synchronized的作用。

答案 2 :(得分:0)

Life_Hacker,

第一路

在函数中使用 static synchronized 关键字在多线程环境中进行类级别锁定。

示例:

public static synchronized void setSomeClass(Artifacts.class) {
   if(isThreadStarted) {
       someClass = someClass1;
   }
}

第二路

在内部功能定义中,您可以创建同步阻止

示例:

public static void setSomeClass(SomeClass = someClass1) {

     synchronized(this){

          if(isThreadStarted) {
            someClass = someClass1;
          }
    }
}

第二种方式是最好的方法