繁体   English   中英

线程-简单的并发问题

[英]Threads - simple concurrency issue

好的,这就是问题所在:以下代码显然不是线程安全的,导致方法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恢复为可运行状态)

线程2:
余额-0、1、2、3、4、5

i-0、1、2、3、4(线程2恢复为可运行状态)

线程1(进入运行状态):balance-... 1,2

我-0、1

(在某些情况下,它可以正常更新,但在50次迭代中必须进行一些异常更新)每个结果如何达到100,这是某种IDE优化来处理线程交织还是什么?


答案:因此,在此示例中无需闩锁,只需线程在打印中“阻塞”,而另一个线程可以同时完成更新。 泰·艾菲

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。

您的计算非常快,启动线程非常慢。 第一个完全在第二个开始之前完成。 输出中的异位数字可能只是操作系统中缓冲区刷新的问题。

添加一个锁存器,以便两个线程实际上同时启动,并使用足够大的数字,您将看到总计没有加起来。

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

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM