确定这是问题:下面的代码显然没有编写线程安全,导致方法increment()不同步。输出变化,并不像:1,2,3,4,5,6 ...
例如输出可以是:1,2,3,4,5,1 ...... 但是它继续像这样6,7,8,......并且达到100.我不明白它怎么能达到100,不应该在第二个1再来2之后,至少在某些情况下,平衡被错误更新由另一个线程。问题是这样的:为什么在1之后它通常以6,7继续......
class Job implements Runnable{
private int balance;
public void run(){
for (int i = 0; i < 50; i++) {
increment();
System.out.println(balance);
int a = 3;
int b = 4;
a = b;
}
}
public void increment(){
int i = balance;
balance = i+1;
}
}
public class ThreadsDemo{
public static void main(String[] args) {
Job job = new Job();
Thread alpha = new Thread(job);
Thread beta = new Thread(job);
alpha.setName("alpha");
beta.setName("beta");
alpha.start();
beta.start();
}
}
进一步解释,这是可能的结果之一:
主题1: 平衡 - 0
i - 0(线程1回到runnable)
线程2:
平衡 - 0,1,2,3,4,5
i - 0,1,2,3,4,(线程2放回运行状态)
线程1(投入运行): 平衡 - ... 1, 2
i - 0,1
(在某些情况下,它可以正常更新,但在50次迭代中,它必须进行一些异常更新) 每个结果如何达到100,这是一些处理线程交错的IDE优化还是什么?
解答: 所以在这个例子中不需要锁存,只是线程在打印时“阻塞”,另一个可以在此期间完成更新。 Ty Affe
class Job implements Runnable{
public int balance = 0;
//public static CountDownLatch latch = new CountDownLatch(1);
public void run(){
for (int i = 0; i < 50000; i++) {
increment();
}
}
public void increment(){
int i = balance;
balance = i+1;
}
}
public class ThreadsDemo{
public static void main(String[] args) {
Job job = new Job();
Thread alpha = new Thread(job);
Thread beta = new Thread(job);
alpha.setName("alpha");
beta.setName("beta");
alpha.start();
beta.start();
try {
alpha.join();
beta.join();
} catch (Exception ex) { }
System.out.println(job.balance +" "+ alpha.isAlive() + " " + beta.isAlive());
}
}
产量约为60 000,正如预期的那样。
答案 0 :(得分:1)
您的计算速度非常快,启动线程非常慢。第一个完成在第二个开始之前完成。输出中的异常数字可能只是操作系统中缓冲区刷新的问题。
添加一个锁存器,以便两个线程实际上同时启动,并使用足够大的数字,并且您将看到总数不会加起来。
public static CountDownLatch latch = new CountDownLatch(1);
private static class Job implements Runnable{
private int balance;
public void run(){
try {
latch.await();
} catch (InterruptedException e) {}
for (int i = 0; i < 50000; i++) {
//existing code
}
}
public void increment(){
int i = balance;
//make it work harder so there's more opportunity for an actual interleave
balance = new BigInteger(Integer.toString(i)).add(BigInteger.ONE).intValue();
}
}
public static void main(String[] args) {
//existing code
alpha.start();
beta.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
latch.countDown();
}