2016-04-09 33 views
0

看看输出,尽管使方法同步,输出没有排序。由于两个线程在堆上增加相同的对象“作业”,无论哪个线程打印该线,结果都应该是增加的值。但为什么它无序地打印?Java线程混乱,为什么输出没有排序?

class TestSync implements Runnable{ 
    private int balance; 

    public void run(){ 
    for(int i=0; i<50; i++) { 
     increment(); 
    System.out.println("balance is "+balance); 
    } 
    } 
    public synchronized void increment(){ 
    balance++;  
    } 
} 


public class TestSyncTest { 

    public static void main(String[] args){ 
    TestSync job = new TestSync(); 
    Thread a = new Thread(job); 
    Thread b = new Thread(job); 
    a.start(); 
    b.start(); 
    } 
} 

输出:

balance is 2 
balance is 3 
balance is 4 
balance is 5 
balance is 6 
balance is 7 
balance is 8 
balance is 9 
balance is 10 
balance is 11 
balance is 12 
balance is 13 
balance is 14 
balance is 15 
balance is 16 
balance is 17 
balance is 18 
balance is 19 
balance is 20 
balance is 21 
balance is 22 
balance is 23 
balance is 24 
balance is 2 
balance is 25 
balance is 27 
balance is 28 
balance is 29 
balance is 26 
balance is 30 
balance is 32 
balance is 33 
balance is 34 
balance is 35 
balance is 36 
balance is 37 
balance is 31 
balance is 38 
balance is 40 
balance is 41 
balance is 42 
balance is 43 
balance is 44 
balance is 39 
balance is 46 
balance is 47 
balance is 45 
balance is 49 
balance is 48 
balance is 50 
balance is 52 
balance is 51 
balance is 53 
balance is 55 
balance is 54 
balance is 56 
balance is 58 
balance is 59 
balance is 60 
balance is 57 
balance is 61 
balance is 62 
balance is 63 
balance is 64 
balance is 65 
balance is 66 
balance is 67 
balance is 68 
balance is 69 
balance is 70 
balance is 71 
balance is 72 
balance is 73 
balance is 74 
balance is 75 
balance is 76 
balance is 77 
balance is 78 
balance is 79 
balance is 80 
balance is 81 
balance is 82 
balance is 83 
balance is 84 
balance is 85 
balance is 86 
balance is 87 
balance is 88 
balance is 89 
balance is 90 
balance is 91 
balance is 92 
balance is 93 
balance is 94 
balance is 95 
balance is 96 
balance is 97 
balance is 98 
balance is 99 
balance is 100 
+0

'synchronized'不承诺订单。它更多的是关于不同线程在代码块上执行的操作的可见性和操作的原子性。这就是为什么。 – Tirath

+0

@Tirath [如果方法调用可以正确排列,保持不重合的调用的相互顺序,而不管线程调用哪个调用,那么执行是非常一致的。换句话说,在方法返回之前,它会与其他线程完全一致地生效。这也被称为'linearizability'或'线程安全'。](http://coldattic.info/shvedsky/pro/blogs/a-foo-walks-into-a-bar/posts/88)。我猜这是java的'synchronized'。所以,订单是否得到保证,取决于你的意思。 –

回答

2

是同步的唯一的事情就是增量。在打印之前读取变量不是,并且打印本身在另一个锁上同步。所以,你可以得到

  • 线程1:增量
  • 线程2:增量
  • 线程1:阅读和打印
  • 线程2:阅读和打印

BTW,余额共享状态,和所有的访问,包括读取所述变量的值,应在同一个锁进行同步。

代码更改为

class TestSync implements Runnable{ 
    private int balance; 

    public void run(){ 
     for(int i = 0; i < 50; i++) { 
      incrementAndPrint(); 
     } 
    } 

    public synchronized void incrementAndPrint(){ 
     balance++;  
     System.out.println("balance is "+balance); 
    } 
} 
+1

println也同步,但不使用相同的锁。 –

+0

所以声明System.out.println(“balance is”+ balance);包括2个步骤:1.读取平衡值并打印。一个线程可以读取该值,但在打印之前被冻结,当它再次被释放时,它会打印它在被冻结之前读取的值。是对的吗 ? – Anudeep

+0

它实际上比原子步骤多得多:读取值,然后将该值连接到一个字符串,该字符串本身需要创建一个新的har数组,将原始字符串的每个char复制到新数组,将该整数转换为一个字符串等等。在每个这些原子步骤之间,线程可能会被调度程序暂停以执行另一个线程。但是,即使整个事件是单个原子操作,因为它是在synchronized块之外完成的,所以线程2可以在thread1打印之前递增。 –

0

同步只保护同步块。这是一个常见的错误,假设如果你在你的程序周围撒一点线程,它会做你想做的。线程安全就像一连串的操作,如果有任何不同步,你的代码可以以任何顺序执行。

但为什么它在无序的方式打印?

线程的目的是同时运行独立的任务。因此,您应该期待有一个或另一个线程执行速度快于另一个线程。

真正的问题应该是;为什么它是有序的。

这是最有可能是由于之前其他一个线程启动。当一个线程正在运行,另一个线程尚未启动时,输出是“有序”的,但是一旦两个线程都在运行,就可以看到竞争状态。

0

你有2个线程打印计数器,应用好的工作,因为你可以看到每一个线程在控制台尽快印刷为一体的想给计数器值,外观等混合起来,因为没有容易的方式格式化或确定哪些值从正在添加的线程...

名称添加到每个线程和打印名字,所以你可以看到数据的来源......

Thread a = new Thread(job, "t1"); 
Thread b = new Thread(job, "t2");