首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具有共享整数对象的线程不按预期工作

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

Stack Overflow用户
提问于 2019-02-18 18:42:59
回答 4查看 353关注 0票数 1

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

代码语言:javascript
复制
First  1
First  2
Second  3
Second  4
First  5
First  6
Second  7
Second  8
First  9
and so on...

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

代码语言:javascript
复制
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();
  }
 }
}

我的主要课程如下

代码语言:javascript
复制
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();

 }
}

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

代码语言:javascript
复制
First  1
First  2
Second  1
Second  2
First  3
First  4
Second  3
Second  4

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

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2019-02-19 03:43:10

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

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

代码语言:javascript
复制
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

票数 -2
EN

Stack Overflow用户

发布于 2019-02-18 18:59:54

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

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

代码语言:javascript
复制
public static Integer num = 1;

public Object lock;
public ThreadDemo(Integer num, Object lock) {
    //this.num = num;
    this.lock =lock;
}
票数 1
EN

Stack Overflow用户

发布于 2019-02-18 18:58:19

您的问题是Integer类是不可变,因此不能在单独的线程中使用它来引用共享值。回答:创建您自己的、可变的、Integer类。

你可以在这里上找到一个类似的问题

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54753524

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档