具有共享整数对象的线程未按预期工作

我有一个问题,我必须以这种格式打印数字。


First  1

First  2

Second  3

Second  4

First  5

First  6

Second  7

Second  8

First  9

and so on...

我已经实现了我的可运行接口,如下所示。


class ThreadDemo implements Runnable {


 public volatile Integer num;


 public Object lock;


 public ThreadDemo(Integer num, Object lock) {

  this.num = num;

  this.lock = lock;

 }


 @Override

 public void run() {


  try {

   while (true) {

    int count = 0;

    synchronized(lock) {

     Thread.sleep(100);

     while (count < 2) {

      System.out.println(Thread.currentThread().getName() + "  " + num++);

      count++;


     }

     lock.notify();

     lock.wait();

    }

   }

  } catch (InterruptedException e) {

   e.printStackTrace();

  }

 }

}

我的主要课程如下


public class CoWorkingThreads {

 private static volatile Integer num = new Integer(1);

 public static void main(String...args) {

  Object lock = new Object();

  Thread thread1 = new Thread(new ThreadDemo(num, lock), "First");

  thread1.start();

  Thread thread2 = new Thread(new ThreadDemo(num, lock), "Second");

  thread2.start();


 }

}

当我运行程序时,我得到如下输出


First  1

First  2

Second  1

Second  2

First  3

First  4

Second  3

Second  4

而不是之前预期的结果。但是当我将整数更改为原子整数类型时,我开始得到预期的结果。谁能解释我可以做些什么来使它使用整数而不是使用原子整数运行


慕斯709654
浏览 97回答 3
3回答

慕慕森

Java Integer 不能通过引用传递。在您的代码中,每个线程都会创建变量的副本。但是 atomicInteger 可以通过引用传递。此外,为了获得正确的结果,您可以将 num 变量更改为静态变量。public static Integer num = 1;public Object lock;public ThreadDemo(Integer num, Object lock) {&nbsp; &nbsp; //this.num = num;&nbsp; &nbsp; this.lock =lock;}

胡子哥哥

仅就您的知识而言,您可能希望尝试使用(s) (例如) 及其相关联的 (s),而不是在 上使用synchronized块。ObjectLockReentrantLockCondition使用Condition(s) 您可以在线程之间以互斥的方式管理共享资源。

缥缈止盈

我仍然认为这个问题没有得到正确回答。这里的缺陷是您从未将共享数据标记为static. 所以每个线程都有自己独立的副本。Integer是一个不可变的包装类,这是真的,但在这种情况下它没有任何关系。让我们深入研究一下num++。该++运算符仅适用于(原始)整数类型。在幕后,num拆箱,++应用,然后将结果分配回num(在装箱转换之后)。该类Integer没有++运算符。事实上,Integer对象是不可变的。不可变意味着每次你增加并创建一个新的值对象。并且该新值对象被分配回您的num引用。但是两个线程有自己的num引用副本,指向不同的Integer盒装原语。因此,它们彼此独立地增加它,而彼此不可见。如果你想在线程之间共享它,你必须static在声明的地方使用访问修饰符。将两个值传递给共享变量是没有意义的。相反,您可以内联初始化它。这是固定版本。public class ThreadDemo implements Runnable {&nbsp; &nbsp; public static Integer num = 1;&nbsp; &nbsp; public static final Object lock = new Object();&nbsp; &nbsp; public ThreadDemo() {&nbsp; &nbsp; }&nbsp; &nbsp; @Override&nbsp; &nbsp; public void run() {&nbsp; &nbsp; &nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while (true) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int count = 0;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; synchronized (lock) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Thread.sleep(100);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while (count < 2) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(Thread.currentThread().getName() + "&nbsp; " + num++);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; count++;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; lock.notify();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; lock.wait();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; } catch (InterruptedException e) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}public class CoWorkingThreads {&nbsp; &nbsp; public static void main(String[] args) {&nbsp; &nbsp; &nbsp; &nbsp; Thread thread1 = new Thread(new ThreadDemo(), "First");&nbsp; &nbsp; &nbsp; &nbsp; thread1.start();&nbsp; &nbsp; &nbsp; &nbsp; Thread thread2 = new Thread(new ThreadDemo(), "Second");&nbsp; &nbsp; &nbsp; &nbsp; thread2.start();&nbsp; &nbsp; }}最后使用客户端提供的锁对象违反了同步策略的封装。所以我改用了内部私有锁对象。这是新的输出。第一 1 第一 2 第二 3 第二 4 第一 5 第一 6 第二 7 第二 8 第一 9 第一 10
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java