线程类的volatile变量不会更新其值,但静态变量

时间:2017-04-18 15:02:40

标签: java multithreading

在下面的代码中,我试图使用多个线程来访问队列,直到isFound = false。我已将isFound变量声明为volatile,并且在某些条件后我将其值更改为true。如果我在一个线程中更改其值,并且根据定义,其更新值应该对所有其他线程可见。运行此代码时,isFound的值仍为false

如果我将isFound从volatile更改为static,它可以正常工作吗?

class FileAccessThread implements Runnable {

    volatile  boolean isFound = false;
    BlockingQueue<String> bq;
        public FileAccessThread(BlockingQueue<String> bq) {
        this.bq = bq;
    }

    public void run() {
        System.out.println("ifFound "+isFound);
        if(bq !=null && !isFound){
            try {
                System.out.println("Current Thread "+Thread.currentThread().getName());
                String filePath = bq.take();
                System.out.println("File Path "+filePath);
                Thread.sleep(2000);

                if(filePath.equals("c:/test/t5.txt")) {
                    isFound = true;
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class MultiFileAccess {

    public static void main(String[] args) {
        ExecutorService e = Executors.newFixedThreadPool(3);
        BlockingQueue<String> bq = new LinkedBlockingQueue<>();
        bq.add("c:/test/t1.txt");
        bq.add("c:/test/t2.txt");
        bq.add("c:/test/t3.txt");
        bq.add("c:/test/t4.txt");
        bq.add("c:/test/t5.txt");
        bq.add("c:/test/t6.txt");
        bq.add("c:/test/t7.txt");
        bq.add("c:/test/t8.txt");
        bq.add("c:/test/t9.txt");
        bq.add("c:/test/t10.txt");

        int lengthOfQueue = bq.size();

        for(int i=0;i < lengthOfQueue-1;i++){
            e.execute(new FileAccessThread(bq));
        }

        e.shutdown();
    }
}

2 个答案:

答案 0 :(得分:3)

我认为你对staticvolatile做了什么有误解。

volatile对变量强加了一组内存读/写语义。在这种情况下,它并不重要,因为您已经使用它自己的变量定义了每个线程,因此每个线程只读取和写入它自己的{{1的本地副本}}

在您将其定义为静态的情况下,所有线程都共享相同的变量 - 因此,如果一个线程更改它,那么其他线程将(可能)看到它。虽然你没有围绕变量进行任何同步,但是关于何时或哪些线程会看到变化是不确定的。

要更深入地了解静态与易失性,请查看此问题的答案:Volatile Vs Static in java

答案 1 :(得分:0)

只需更改实例化Runnable的方式:

Runnable oneInstanceOnly = new FileAccessThread(bq);
for(int i=0;i < lengthOfQueue-1;i++){
    e.execute(oneInstanceOnly);
}

您创建了许多实例,每个实例都有自己的isFound字段,除非创建为static