Java线程共享静态变量

时间:2018-10-29 14:16:51

标签: java multithreading

有一个线程可以在静态变量tracking为true的情况下继续跟踪新电子邮件。看起来像这样:

Thread thread = new Thread(new Runnable() {

    @Override
    public void run() {
        try  {
            tracking = true;
            while(tracking){
                //check emails
             }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
});

我实现了一个停止跟踪电子邮件的功能,该功能基本上将tracking设置为false。

跟踪只是一个private static boolean,我只在执行这些任务的类中使用。

这种方法会导致我遇到任何问题吗?

3 个答案:

答案 0 :(得分:4)

  

这种方法会导致我遇到任何问题吗?

是的。

您面临的是“可见性”问题。在最高级别,“可见性”是您的线程查看其他线程执行的修改的能力。如果要获得可见性,就Java规范而言,您需要在值读取和值写入之间建立“关系发生前的机会”。没有这种关系,就不能保证对tracking变量的任何写操作都可以被执行写操作的线程以外的任何其他线程看到。

在您的情况下,我想到了两种可能性来确定恋爱之前发生的事情:

  1. 您在布尔值volatile的声明中添加了布尔值(无需进一步更改程序)
  2. 您将布尔值转换为AtomicBoolean(然后可以将其声明为final,然后使用tracking.set(false)禁用跟踪,并使用tracking.get()检查是否仍应跟踪)。

需要明确的是:无需执行两项更改,而是一项或另一项。

其他可能性包括:用java.util.Lock保护您的读写,但这太过分了。

您可以在此处了解更多信息:How to understand happens-before consistent

答案 1 :(得分:3)

如果有多个线程读写同一变量,则需要使用同步(例如AtomicBoolean)。在这种特殊情况下,将tracking声明为volatile就足够了,这样一个线程中设置为该变量的新值将在另一个线程中正确可见:

private static volatile boolean tracking;

答案 2 :(得分:3)

如果这是使用tracking only 线程,而您只是将其用作终止该线程的一种方式,那么您可能还可以,尽管它仍然很麻烦。当您将tracking设置为false时,它可能会循环多次,但最终将显示为false(除非它在某处恢复为true,如下所述),然后它将终止。

但是,如果有多个使用tracking的线程,那么即使您使用volatileAtomicBoolean,这对您来说也绝对是一个问题。

如果您将tracking设置为false,但是之后紧接着又有Runnable个运行并且将tracking设置为true,

 public void run() {
    try  {
        tracking = true; // <-- sets tracking back to true
        while(tracking){
            //check emails
        }

然后您尝试终止的线程将不会终止,因为tracking再次为真。

在再次将tracking设置为true之前,您需要确保所有线程都已正确停止。同步和锁定可以帮助解决这个问题。