2013-11-28 98 views
0

好吧,这是问题:下面的代码显然不是写成线程安全的,导致方法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

我 - 0,1,2,3,4,(2线放回到可运行)

线程1(投入运行): 平衡 - ... 1,

我 - 0,1

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


答: 因此,在这个例子中,没有必要锁,只是线程被打印上“堵”,而另一个可以在此期间完成更新。 Ty情绪

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

正如预期的那样,产量约为6万。

回答

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

} 
+0

我现在正在实施它。 – croraf

+0

请注意,为什么你可能看到相同的数字打印出来不止一次的原因是完全可能的是,执行连续两次运行“increment()”,然后连续运行两次“print”(尽管打印到不同的缓冲区)。 – creichen

+0

好吧,我把闩锁(即使我不明白它),它总是加起来100000,(一次99999),它应该有更大的差异,你不这么认为。线程应该交错,并且做出错误的结果。我每次都得到正确的结果怎么可能?我怎样才能把正确的代码放在评论中。 – croraf