我正在尝试交替使用 2 个不同的线程打印奇数和偶数。我能够使用等待、通知和同步块来实现它,但现在我想评估我们是否可以在不使用等待、通知和同步的情况下实现它。
以下是我的代码,但它不起作用:
public class OddEvenUsingAtomic {
AtomicInteger nm = new AtomicInteger(0);
AtomicBoolean chk = new AtomicBoolean(true);
public static void main(String args[]) {
final OddEvenUsingAtomic pc = new OddEvenUsingAtomic();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (pc.chk.compareAndSet(true, false)) {
System.out.println("Odd: " + pc.nm.incrementAndGet());
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while (true) {
if (pc.chk.compareAndSet(false, true)) {
System.out.println("Even: " + pc.nm.incrementAndGet());
}
}
}
}).start();
}
}
有任何想法吗?
根据布鲁诺的建议,我创建了另一个版本,该版本似乎效果更好:
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class OddEvenUsingAtomic {
AtomicInteger nm = new AtomicInteger(0);
AtomicBoolean chk = new AtomicBoolean(true);
public static void main(String args[]) {
final OddEvenUsingAtomic pc = new OddEvenUsingAtomic();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (pc.chk.get() == Boolean.TRUE) {
System.out.println("Odd: " + pc.nm.incrementAndGet());
pc.chk.compareAndSet(true, false);
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while (true) {
if (pc.chk.get() == Boolean.FALSE) {
System.out.println("Even: " + pc.nm.incrementAndGet());
pc.chk.compareAndSet(false, true);
}
}
}
}).start();
}
}
代码没有正确同步,这就是问题所在。
您的代码中允许使用以下执行顺序:
- 第一个线程看到
chk == true
,将其设置为false
并输入if
block.
- 第二个线程看到
chk == false
,将其设置为true
并输入if
block.
现在,你有 2 个线程都在它们的内部if
块,准备:
-
incrementAndGet()
号码
- 打印出来。
因此,您完全无法控制将要发生的事情。
- 您可以让任何线程调用
incrementAndGet()
,因此您可以使用线程“奇数”打印,首先打印奇数,然后打印偶数。
- 您可以让第一个线程打印数字,循环,查看条件是否再次满足(因为第二个线程已设置
chk
to true
再次打印,所有这些都在第二个线程有机会打印之前完成)。
正如您所看到的,为了达到您想要的结果,您必须以原子方式完成以下操作:
-
compareAndSet()
布尔值
-
incrementAndGet()
号码
- print it
如果这 3 个操作不是原子的,那么您可以安排线程以任何可能的顺序运行操作,但您无法控制输出。实现此目的最简单的方法是使用同步块:
public static void main(final String... args) {
final Object o = new Object();
// ... thread 1 ...
synchronized(o) {
if (boolean is in the expected state) { change boolean, get number, increment, print }
}
// ... thread 2 ...
synchronized(o) {
if (boolean is in the expected state) { change boolean, get number, increment, print }
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)