java - java中的 volatile 关键字对其他线程不可见,下面是我的代码

标签 java multithreading

当我在线程 T1 中更新 i 的值时,该值对线程 T2 不可见 - 为什么?理论上, volatile 变量必须检索新值,但它不起作用。

    class Threads implements Runnable
    {

      public volatile int i=4;
      volatile int j=0;
      int x=0;

      public static void main(String[] args) {
        Threads th=new Threads();
        Thread a = new Thread(th);
        Thread b=new Thread(th);
        a.setName("T1");
        a.setPriority(Thread.MAX_PRIORITY);
        b.setName("T2");
        a.start();
        b.start();
      }

      public int count() {
        return ++i;
      }

      public void run() {
        while(j<=10)
        {

          if(Thread.currentThread().getName().equals("T1"))
          {
            i++;
            System.out.println(Thread.currentThread().getName()+" : "+i);

           try
           {
             Thread.sleep(2);
           }catch(Exception ex){}
         }
         else if(Thread.currentThread().getName().equals("T2"))
         {

           System.out.println(Thread.currentThread().getName()+" : "+i);
           try
           {
             Thread.sleep(1);
           }catch(Exception ex){}
         }

         j++;
       }
      }
    }

最佳答案

我不知道您希望代码输出什么,但是:

请注意,即使变量是 volatile 的,x++x = x + 1 的快捷方式。它不是原子的,并且执行单独的读取和写入操作,该值可能会被两个操作之间的另一个线程更改。

在你的情况下,对于变量 i ,只有一个线程正在写入变量,因此这应该不是问题。

但是对于 j ,两个线程正在执行 j++在同一个变量上。对于某些迭代,一个线程有可能写入 j另一个线程的读写之间。导致之前的写入被忽略。

为了避免这种情况,您可以:

  • 执行j++synchronized block
  • 使用AtomicInteger而不是volatile int

还有一点就是j <= 10上的测试在增量之前完成。所以两个线程可能会进入while对于 j==10 时的迭代,结果是 j==12 (或者当还涉及上述效果时甚至会有所不同)。

要解决这个问题,您可以直接在 while 中递增条件,使用 AtomicInteger例如:

while(j.getAndIncrement() <= 10)

关于java - java中的 volatile 关键字对其他线程不可见,下面是我的代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25626111/

相关文章:

java - 如何对重复项进行分组? lambda 8 Java

java - 理解Java中的对象

c++ - 为什么链表不是线程安全的?

c++ - 尝试创建线程安全的 std::map

java - 持有多个锁的线程进入 wait() 状态。它会释放所有持有的锁吗?

java - 将输入保存到文件

java - 如何更改 Java 中的默认类加载器?

multithreading - Visual C++ (CLI) 线程

java - 在Windows下的java中创建目录的硬链接(hard link)

c# - 如何在不同线程中使用 Entity Framework ?