使用 System.out.println(Thread.currentThread().getName() + " " +count);导致同步
Using System.out.println(Thread.currentThread().getName() + " " +count); leads to synchronization
我在 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());
}
}
当多个线程试图同时访问同一字段时,线程之间会发生同步问题。
如果不进行打印,run
方法将处于一个几乎连续访问计数器的紧密循环中。让多个线程在没有同步的情况下做那个,很容易出错。
通过添加打印,您正在改变循环,使其大部分(几乎所有)时间都用于打印,只是偶尔增加计数。这不太可能引起争用。
代码在打印方面仍然存在问题,唯一的区别是争用发生的频率要低得多,而且您仅对 1000
循环进行的测试不足以证明该问题。您可能必须 运行 几年后线程才会发生冲突。
这是一个经典的演示,说明为什么线程问题如此难以查找和修复。该循环(带有它的 print 语句)可以 运行 在多个线程上运行多年而不会发生争用,但如果线程之间只发生一次冲突,那么代码就会中断。想象一下,这发生在心脏起搏器、卫星或核电站中!
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;
}
}
我在 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());
}
}
当多个线程试图同时访问同一字段时,线程之间会发生同步问题。
如果不进行打印,run
方法将处于一个几乎连续访问计数器的紧密循环中。让多个线程在没有同步的情况下做那个,很容易出错。
通过添加打印,您正在改变循环,使其大部分(几乎所有)时间都用于打印,只是偶尔增加计数。这不太可能引起争用。
代码在打印方面仍然存在问题,唯一的区别是争用发生的频率要低得多,而且您仅对 1000
循环进行的测试不足以证明该问题。您可能必须 运行 几年后线程才会发生冲突。
这是一个经典的演示,说明为什么线程问题如此难以查找和修复。该循环(带有它的 print 语句)可以 运行 在多个线程上运行多年而不会发生争用,但如果线程之间只发生一次冲突,那么代码就会中断。想象一下,这发生在心脏起搏器、卫星或核电站中!
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;
}
}