为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

慕斯709654 2022-06-23 19:23:48
我有一个问题,我必须以这种格式打印数字。First  1First  2Second  3Second  4First  5First  6Second  7Second  8First  9and 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  1First  2Second  1Second  2First  3First  4Second  3Second  4而不是之前预期的结果。但是当我将整数更改为原子整数类型时,我开始得到预期的结果。谁能解释我可以做些什么来使它使用整数而不是使用原子整数运行
查看完整描述

3 回答

?
慕慕森

TA贡献1856条经验 获得超17个赞

Java Integer 不能通过引用传递。在您的代码中,每个线程都会创建变量的副本。但是 atomicInteger 可以通过引用传递。


此外,为了获得正确的结果,您可以将 num 变量更改为静态变量。


public static Integer num = 1;


public Object lock;

public ThreadDemo(Integer num, Object lock) {

    //this.num = num;

    this.lock =lock;

}


查看完整回答
反对 回复 2022-06-23
?
胡子哥哥

TA贡献1825条经验 获得超6个赞

仅就您的知识而言,您可能希望尝试使用(s) (例如) 及其相关联的 (s),而不是在 上使用synchronized块。ObjectLockReentrantLockCondition

使用Condition(s) 您可以在线程之间以互斥的方式管理共享资源。


查看完整回答
反对 回复 2022-06-23
?
缥缈止盈

TA贡献2041条经验 获得超4个赞

我仍然认为这个问题没有得到正确回答。这里的缺陷是您从未将共享数据标记为static. 所以每个线程都有自己独立的副本。Integer是一个不可变的包装类,这是真的,但在这种情况下它没有任何关系。让我们深入研究一下num++。该++运算符仅适用于(原始)整数类型。在幕后,num拆箱,++应用,然后将结果分配回num(在装箱转换之后)。该类Integer没有++运算符。事实上,Integer对象是不可变的。


不可变意味着每次你增加并创建一个新的值对象。并且该新值对象被分配回您的num引用。但是两个线程有自己的num引用副本,指向不同的Integer盒装原语。因此,它们彼此独立地增加它,而彼此不可见。如果你想在线程之间共享它,你必须static在声明的地方使用访问修饰符。将两个值传递给共享变量是没有意义的。相反,您可以内联初始化它。这是固定版本。


public class ThreadDemo implements Runnable {

    public static Integer num = 1;


    public static final Object lock = new Object();


    public ThreadDemo() {

    }


    @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 {

    public static void main(String[] args) {

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

        thread1.start();

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

        thread2.start();

    }

}

最后使用客户端提供的锁对象违反了同步策略的封装。所以我改用了内部私有锁对象。


这是新的输出。


第一 1 第一 2 第二 3 第二 4 第一 5 第一 6 第二 7 第二 8 第一 9 第一 10


查看完整回答
反对 回复 2022-06-23
  • 3 回答
  • 0 关注
  • 96 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信