具有共享整数对象的线程未按预期工作
Threads with shared integer object not working as expected
我有一个问题,我必须以这种格式打印数字。
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();
}
}
}
我的主要class如下
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
而不是之前预期的结果。但是当我将整数更改为原子整数类型时,我开始得到预期的结果。任何人都可以解释我可以做些什么来使它 运行 与整数而不是使用原子整数
您的问题是整数 class 是 Immutable,因此您不能在单独的线程中使用它来引用共享值。答案:创建您自己的可变整数 class.
您可以在 SO here
上找到类似问题的答案
Java 不能通过引用传递整数。在您的代码中,每个线程都会创建该变量的副本。但是 atomicInteger 可以通过引用传递。
另外,为了获得正确的结果,您可以将 num 变量更改为静态变量。
public static Integer num = 1;
public Object lock;
public ThreadDemo(Integer num, Object lock) {
//this.num = num;
this.lock =lock;
}
仅供参考,您可能想在 Object
上尝试使用 Lock
(s)(例如 ReentrantLock
,而不是使用 synchronized
块) 及其关联的 Condition
(s).
使用 Condition
(s),您可以在线程之间以互斥方式管理您的共享资源。
我仍然认为这个问题没有得到正确回答。这里的缺陷是您从未将共享数据标记为 static
。所以每个线程都有自己的独立副本。 Integer
是一个不可变的包装器 class,这是正确的,但在这种情况下它没有任何作用。让我们更深入地了解 num++
。 ++
运算符仅适用于(原始)整数类型。在幕后,num
被取消装箱,应用 ++
,然后将结果分配回 num
(装箱转换后)。 Integer
class 没有 ++
运算符。事实上,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();
}
}
最终使用客户端提供的锁对象违反了同步策略的封装。所以我改用了内部私有锁对象。
这是新的输出。
First 1 First 2 Second 3 Second 4 First 5 First 6 Second 7
Second 8 First 9 First 10
我有一个问题,我必须以这种格式打印数字。
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();
}
}
}
我的主要class如下
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
而不是之前预期的结果。但是当我将整数更改为原子整数类型时,我开始得到预期的结果。任何人都可以解释我可以做些什么来使它 运行 与整数而不是使用原子整数
您的问题是整数 class 是 Immutable,因此您不能在单独的线程中使用它来引用共享值。答案:创建您自己的可变整数 class.
您可以在 SO here
上找到类似问题的答案Java 不能通过引用传递整数。在您的代码中,每个线程都会创建该变量的副本。但是 atomicInteger 可以通过引用传递。
另外,为了获得正确的结果,您可以将 num 变量更改为静态变量。
public static Integer num = 1;
public Object lock;
public ThreadDemo(Integer num, Object lock) {
//this.num = num;
this.lock =lock;
}
仅供参考,您可能想在 Object
上尝试使用 Lock
(s)(例如 ReentrantLock
,而不是使用 synchronized
块) 及其关联的 Condition
(s).
使用 Condition
(s),您可以在线程之间以互斥方式管理您的共享资源。
我仍然认为这个问题没有得到正确回答。这里的缺陷是您从未将共享数据标记为 static
。所以每个线程都有自己的独立副本。 Integer
是一个不可变的包装器 class,这是正确的,但在这种情况下它没有任何作用。让我们更深入地了解 num++
。 ++
运算符仅适用于(原始)整数类型。在幕后,num
被取消装箱,应用 ++
,然后将结果分配回 num
(装箱转换后)。 Integer
class 没有 ++
运算符。事实上,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();
}
}
最终使用客户端提供的锁对象违反了同步策略的封装。所以我改用了内部私有锁对象。
这是新的输出。
First 1 First 2 Second 3 Second 4 First 5 First 6 Second 7 Second 8 First 9 First 10