使用System.out.println(Thread.currentThread()。getName()+"" + count);导致同步

时间:2017-05-25 06:37:47

标签: java multithreading synchronization synchronized

我正在学习java中的多线程,在教程中,它说删除synchronized会使程序错误而且确实如此,所以我只是在试验并编写了一条打印行System.out.println(Thread.currentThread().getName() + " " +count); 并删除了同步的单词,即使这样程序运行正常。但是,如果仅删除同步字并且未添加打印行(System.out.println(Thread.currentThread().getName() + " " +count);),则该程序会出现错误广告。

我无法理解添加打印行如何使其同步。

public class intro implements Runnable {

    int n=10000; 
    private int count = 0; 

    public int getCount() { return count; }

    public synchronized void incrSync() { count++;  }

    public void run () {
        for (int i=0; i<n; i++) {
            incrSync();
            //System.out.println(Thread.currentThread().getName() + "  " +count);       
        } 
        } 


    public static void main(String [] args) {

        intro mtc = new intro();
        Thread t1 = new Thread(mtc);
        Thread t2 = new Thread(mtc);
        t1.start();
        t2.start();
        try {
            t1.join();

            t2.join();

        } catch (InterruptedException ie) {
        System.out.println(ie);
        ie.printStackTrace();
    }
    System.out.println("count = "+ mtc.getCount());
}
}

2 个答案:

答案 0 :(得分:2)

当多个线程同时尝试访问同一字段时,线程之间会发生同步问题

如果没有打印,run方法几乎连续不断地进入计数器。使多个线程在没有同步的情况下执行此操作很可能会导致错误。

通过添加打印,您正在更改循环以花费大部分时间(几乎所有时间)进行打印,并且仅偶尔增加计数。这不太可能导致争用。

代码仍然存在打印错误,唯一的区别是争用发生的频率要低得多,而仅仅1000循环的测试不足以证明问题。在线程发生冲突之前,您可能需要运行它几年。

这是为什么线程问题很难找到并修复的经典演示。该循环(使用它的print语句)可以在多个线程上运行多年而不会发生争用但如果线程之间只发生一次冲突则代码会中断。想象一下,心脏起搏器,卫星或核电站发生了这种情况!

答案 1 :(得分:0)

println方法调用newline,这是一个带synchronized块的方法。它给出了正确的结果,虽然它不是线程安全的。

同时考虑T1读取计数5和T2读取计数5,然后发生竞争条件。它正在给出正确的结果,因为您正在使用阻塞的System.out.println(Thread.currentThread().getName() + " " +count);。增加线程数。

 private void newLine() {
    try {
        synchronized (this) {
            ensureOpen();
            textOut.newLine();
            textOut.flushBuffer();
            charOut.flushBuffer();
            if (autoFlush)
                out.flush();
        }
    }
    catch (InterruptedIOException x) {
        Thread.currentThread().interrupt();
    }
    catch (IOException x) {
        trouble = true;
    }
}