这是我的代码:
public class MyRunnableClass implements Runnable {
static int x = 25;
int y = 0;
private static final Object sharedLock = new Object();
@Override
public void run() {
while(x>0){
someMethod();
}
}
public synchronized void someMethod(){
synchronized (sharedLock){
x--;
y++;
}
}
}
和测试类:
public class MyRunnableClassTest {
public static void main(String[] args) throws InterruptedException {
MyRunnableClass aa = new MyRunnableClass();
MyRunnableClass bb = new MyRunnableClass();
Thread a = new Thread(aa);
Thread b = new Thread(bb);
a.start();
b.start();
a.join();
b.join();
System.out.println(aa.y + bb.y);
}
}
当我运行此代码时,我看到输出25很好,但当x为250时,我看到251 ..为什么?为什么不250?
答案 0 :(得分:3)
您必须扩展synchronized
范围,以便涵盖x
上的读取操作:
@Override
public void run() {
for (;;) {
synchronized (sharedObject) {
if (x <= 0) break;
someMethod();
}
}
}
答案 1 :(得分:2)
重合。 25
可能会发生同样的事情,就像任何其他数字一样。
例如,在执行
期间while(x>0){
someMethod();
}
没有同步,在一堆循环之后,让x
为1.第一个线程开始迭代(进入正文),然后线程切换,第二个线程看到x
是1,所以进入循环体。两者都会递增计数,它们的总和将等于原始x
值的一个。
这是一种竞争条件,你恰好可以通过更大的数字更容易看到后果。
答案 2 :(得分:1)
当你这样做时:
while(x>0){
someMethod();
}
让我们说x = 1和:
线程A评估x&gt; 0到true,进入循环。 让我们说线程A在下一行执行之前被中断。 线程B也将评估x> 1。 0到true并进入循环。
两者都将一个接一个递减x并递增y。
要解决此问题,请检查x&gt; 0也必须在锁中。
例如:
public class MyRunnableClass implements Runnable {
static int x = 25;
int y = 0;
private static final Object sharedLock = new Object();
@Override
public void run() {
while(x>0){
someMethod();
}
}
public synchronized void someMethod(){
synchronized (sharedLock){
if(x > 0){
x--;
y++;
}
}
}
}
答案 3 :(得分:1)
有时,线程a和线程b都可以调用someMethod(),因为x是1.一个线程锁定sharedLock,使x等于0,y等于250,然后释放sharedLock,此时其他线程调用someMethod()并使y等于251,x等于-1。
答案 4 :(得分:0)
您也可以使用AtomicInteger
解决该问题:
import java.util.concurrent.atomic.AtomicInteger;
public class MyRunnableClass implements Runnable {
private static final AtomicInteger xHolder = new AtomicInteger(25);
int y = 0;
@Override
public void run() {
while (xHolder.decrementAndGet() >= 0) {
y++;
}
}
public static void main(String[] args) throws InterruptedException {
MyRunnableClass aa = new MyRunnableClass();
MyRunnableClass bb = new MyRunnableClass();
Thread a = new Thread(aa);
Thread b = new Thread(bb);
a.start();
b.start();
a.join();
b.join();
System.out.println(aa.y + bb.y);
}
}
或者使用一些扩展的并行性进行测试:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
public class MyRunnableClass implements Callable<Integer> {
private static final AtomicInteger xHolder = new AtomicInteger(250000);
int y = 0;
@Override
public Integer call() throws Exception {
while (xHolder.decrementAndGet() >= 0) {
y++;
}
System.out.println(Thread.currentThread().getName() + " returns " + y);
return y;
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newCachedThreadPool();
ExecutorCompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(
executorService);
int parallelism = 5;
for (int i = 0; i < parallelism; ++i) {
completionService.submit(new MyRunnableClass());
} // for
int ySum = 0;
for (int j = 0; j < parallelism; ++j) {
Future<Integer> future = completionService.take();
ySum += future.get();
} // for
System.out.println(ySum);
executorService.shutdown();
}
}
输出:
pool-1-thread-3 returns 26619
pool-1-thread-5 returns 0
pool-1-thread-1 returns 104302
pool-1-thread-2 returns 95981
pool-1-thread-4 returns 23098
250000