共享整数对象的线程无法按预期工作

问题描述 投票:1回答:4

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

First  1
First  2
Second  3
Second  4
First  5
First  6
Second  7
Second  8
First  9
and so on...

我已经实现了我的runnable接口,如下所示。

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

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

java multithreading java-threads atomicinteger
4个回答
-1
投票

我仍然认为这个问题没有得到正确回答。这里的缺陷是你从未将共享数据标记为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后2后4前5前5后6后7后8前9后10


1
投票

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

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

public static Integer num = 1;

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

0
投票

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

您可以在SO here上找到类似的问题


0
投票

仅仅为了你的知识,而不是在synchronized上使用Object块,你可能想要试验Lock(s)(例如ReentrantLock)及其相关的Condition(s)。

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

© www.soinside.com 2019 - 2024. All rights reserved.