线程 - 简单的并发问题

时间:2013-11-28 20:50:09

标签: java multithreading

确定这是问题:下面的代码显然没有编写线程安全,导致方法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,正如预期的那样。

1 个答案:

答案 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();

}