Java 线程-简单并发问题

Java 线程-简单并发问题,java,multithreading,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; publ

好的,这就是问题所在:下面的代码显然不是线程安全的,因为方法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();

}
}
类作业实现可运行{
私人国际收支平衡;
公开募捐{
对于(int i=0;i<50;i++){
增量();
系统输出打印项次(余额);
INTA=3;
int b=4;
a=b;
}
}
公共空间增量(){
int i=平衡;
余额=i+1;
}
}
公共类ThreadsDemo{
公共静态void main(字符串[]args){
作业=新作业();
线程alpha=新线程(作业);
线程beta=新线程(作业);
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(投入运行): 平衡-。。。1,2

i-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());
}
}
类作业实现可运行{
公共整数余额=0;
//公共静态倒计时闩锁=新倒计时闩锁(1);
公开募捐{
对于(int i=0;i<50000;i++){
增量();
}
}
公共空间增量(){
int i=平衡;
余额=i+1;
}
}
公共类ThreadsDemo{
公共静态void main(字符串[]args){
作业=新作业();
线程alpha=新线程(作业);
线程beta=新线程(作业);
alpha.setName(“alpha”);
beta.setName(“beta”);
alpha.start();
beta.start();
试一试{
alpha.join();
beta.join();
}捕获(例外情况除外){}
System.out.println(job.balance+“”+alpha.isAlive()+“”+beta.isAlive());
}
}

正如预期的那样,输出大约为60000。

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

添加一个闩锁,使两个线程实际上同时启动,并使用足够大的数字,您将看到一个总数不相加

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

}
publicstaticcountdownlatch闩锁=新的CountDownLatch(1);
私有静态类作业实现可运行{
私人国际收支平衡;
公开募捐{
试一试{
satch.wait();
}捕获(中断异常e){}
对于(int i=0;i<50000;i++){
//现行守则
}
}
公共空间增量(){
int i=平衡;
//让它更难工作,这样就有更多的机会进行实际的交织
balance=new biginger(Integer.toString(i)).add(biginger.ONE).intValue();
}
}
公共静态void main(字符串[]args){
//现行守则
alpha.start();
beta.start();
试一试{
睡眠(100);
}捕获(中断异常e){}
倒计时();
}

我现在正在实现它。请注意,您可能会多次看到同一个数字被打印出来的原因是,执行完全有可能在一行中运行两次
increment()
,然后在一行中运行两次
print
(尽管打印到不同的缓冲区)。好的,我放置了一个闩锁(即使我不明白),加起来总有10万(一次是99 999),它应该有更大的差异,你不这么认为。线程应该交错,并产生错误的结果。我怎么可能每次都得到正确的结果?我怎么能把正确的代码放在注释中。我真的不希望差异大于1或2,不。你认为现代计算机需要多长时间来计数50000?需要做一些更复杂的事情才能看到更大的差异。请参见编辑。顺便说一句,您还可以通过让他们在每次通过时打印数字来显著减少交织的数量。这是一个漫长而缓慢的操作,他们都必须停下来等待,因此,两个都不太可能同时递增同时,通常一个是递增的,而另一个是等待println。如果您只在末尾打印一次余额,您将看到一个数字的偏移量要大得多。