System.out.println()为什么会影响到多线程?

七月这天 2013-11-22 06:57:14
public class EvenCheckerEasy implements Runnable {

private static int val = 0;

@Override
public void run() {
while (true) {
++val;
++val;
System.out.println(val); // 在我电脑上测试,此处添加打印输出似乎防止了并发的产生,为什么?
if (val % 2 != 0) {
System.out.println(val + " not event!");
return;
}
}
}

public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
exec.execute(new EvenCheckerEasy());
}
exec.shutdown();
}
}
...全文
791 25 打赏 收藏 转发到动态 举报
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
dongqinging 2015-11-17
  • 打赏
  • 举报
回复
System.out.println(x); 打印完下,,就释放out锁,等待下一次获取
七月这天 2013-11-26
  • 打赏
  • 举报
回复
引用 23 楼 zxcvbnm11920 的回复:
[quote=引用 22 楼 qiyuezhetian 的回复:]
public void run() {
		while (true) {
			++val;
			++val;
			// System.out.println(val);
			synchronized (System.out) {
			}
			if (val % 2 != 0) {
				System.out.println(val + " not event!");
				return;
			}
		}
	}
我可以这么理解吗?还是不行啊!
理解是可以这么理解的,但是实际情况还有事情需求考虑。 synchronized (System.out) {}这里一定要有耗时操作,时间必须超过new10次的时间 EvenCheckerEasy(),因为按你这样写,第一个start走到synchronized (System.out)时,如果有一个EvenCheckerEasy刚刚开始start,第一个判断val % 2 != 0前,正好这个个EvenCheckerEasy刚做一次++val,这个线程还没有开始竞争锁操作,第一个线程正好val变成单数了。 你可以用这样代码注释下下前后对比。

public void run() {
        while (true) {
            ++val;
            ++val;
            synchronized (System.out) {//注释掉这行测试
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }//注释掉这行测试
            if (val % 2 != 0) {
                System.out.println(val + " not event!");
                return;
            }
        }
    }
当原理很明确的时候,出现奇怪现象,你只要逐行看看你的代码,你自己就能想清楚为什么出现这个情况。[/quote] good,解释的很清楚!
骑士的崛起 2013-11-26
  • 打赏
  • 举报
回复
引用 22 楼 qiyuezhetian 的回复:
public void run() {
		while (true) {
			++val;
			++val;
			// System.out.println(val);
			synchronized (System.out) {
			}
			if (val % 2 != 0) {
				System.out.println(val + " not event!");
				return;
			}
		}
	}
我可以这么理解吗?还是不行啊!
理解是可以这么理解的,但是实际情况还有事情需求考虑。 synchronized (System.out) {}这里一定要有耗时操作,时间必须超过new10次的时间 EvenCheckerEasy(),因为按你这样写,第一个start走到synchronized (System.out)时,如果有一个EvenCheckerEasy刚刚开始start,第一个判断val % 2 != 0前,正好这个个EvenCheckerEasy刚做一次++val,这个线程还没有开始竞争锁操作,第一个线程正好val变成单数了。 你可以用这样代码注释下下前后对比。

public void run() {
        while (true) {
            ++val;
            ++val;
            synchronized (System.out) {//注释掉这行测试
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }//注释掉这行测试
            if (val % 2 != 0) {
                System.out.println(val + " not event!");
                return;
            }
        }
    }
当原理很明确的时候,出现奇怪现象,你只要逐行看看你的代码,你自己就能想清楚为什么出现这个情况。
Amarantine_LT 2013-11-25
  • 打赏
  • 举报
回复
Hi, 我做了个实验,我发现没有打印方法的代码更容易出现奇数退出程序。但并不是说有System的代码不会出现奇数。 请用调试模式启动System打印的代码,在not event处打上断点。立即会得到断点进入,并且完成线程退出。这可以说明这条语句没有造成妨碍并发,只是使得并发更难发生。至于为什么更难,我也不太清楚。
genganpeng 2013-11-25
  • 打赏
  • 举报
回复
引用 楼主 qiyuezhetian 的回复:
public class EvenCheckerEasy implements Runnable {

	private static int val = 0;

	@Override
	public void run() {
		while (true) {
			++val;
			++val;
			System.out.println(val); // 在我电脑上测试,此处添加打印输出似乎防止了并发的产生,为什么?
			if (val % 2 != 0) {
				System.out.println(val + " not event!");
				return;
			}
		}
	}

	public static void main(String[] args) {
		ExecutorService exec = Executors.newCachedThreadPool();
		for (int i = 0; i < 10; i++) {
			exec.execute(new EvenCheckerEasy());
		}
		exec.shutdown();
	}
}
其实并没有阻止并发,将程序改成这样
private static int val = 0;
	private int i = 10;

	@Override
	public void run() {
		while (i-- > 0) {
			++val;
			++val;
			System.out.println(Thread.currentThread().getId() + ":" + val); // 在我电脑上测试,此处添加打印输出似乎防止了并发的产生,为什么?
			if (val % 2 != 0) {
				System.out.println(val + " not event!");
				return;
			}
		}
	}
得到的结果是 10:10 10:68 10:70 10:72 10:74 10:76 10:78 10:8 10:80 10:84 11:116 11:118 11:120 11:122 11:124 11:26 11:28 11:30 11:34 11:8 12:152 12:156 12:168 12:170 12:174 12:178 12:182 12:186 12:190 12:90 13:114 13:126 13:128 13:130 13:132 13:162 13:32 13:36 13:38 13:40 14:22 14:50 14:52 14:54 14:56 14:58 14:60 14:62 14:64 14:66 15:100 15:102 15:104 15:106 15:108 15:110 15:112 15:46 15:96 15:98 16:136 16:138 16:140 16:142 16:144 16:146 16:148 16:150 16:158 16:92 17:154 17:172 17:180 17:188 17:192 17:194 17:196 17:198 17:200 17:82 8:134 8:160 8:164 8:166 8:176 8:184 8:52 8:86 8:90 8:94 9:12 9:14 9:16 9:18 9:20 9:24 9:42 9:46 9:48 9:8 可以看出线程间还是交叉运行的,val++的操作都执行完了,我觉得可能是每个线程都在等待IO的调用,所以获得数都是偶数,这个应该跟线程与IO调用关系有关
骑士的崛起 2013-11-25
  • 打赏
  • 举报
回复
又是一个讨论离题的帖子,查下源代码就知道原因了。

public void println(int x) {
	synchronized (this) {
	    print(x);
	    newLine();
	}
}
rumlee 2013-11-25
  • 打赏
  • 举报
回复
引用 10 楼 qiyuezhetian 的回复:
[quote=引用 4 楼 rumlee 的回复:] 这里并非因为阻塞了,而是因为两个++val执行所需要的时间太小了,而造成了你的一种错觉。 你在++val中间加上一行try{ Thread.sleep(100); }catch(Exception e){} 很快你就会发现最终只有一个线程在跑了,其它9个都会在很短的时间内结束掉。
那还是不明白,其他的9个线程都结束了,为什么还有一个线程没有产生并发呢?[/quote] 一个线程何来并发?
七月这天 2013-11-25
  • 打赏
  • 举报
回复
引用 21 楼 zxcvbnm11920 的回复:
[quote=引用 19 楼 qiyuezhetian 的回复:] 仓促就结贴了,细想下觉得还是不对,能解释的更详细点吗?
System.out这个获得的都是同一个对象,synchronized (this)用这个锁就能保证异步了,不会同步执行。 多写点多线程例子,就能很容易理解。[/quote]
public void run() {
		while (true) {
			++val;
			++val;
			// System.out.println(val);
			synchronized (System.out) {
			}
			if (val % 2 != 0) {
				System.out.println(val + " not event!");
				return;
			}
		}
	}
我可以这么理解吗?还是不行啊!
骑士的崛起 2013-11-25
  • 打赏
  • 举报
回复
引用 19 楼 qiyuezhetian 的回复:
仓促就结贴了,细想下觉得还是不对,能解释的更详细点吗?
System.out这个获得的都是同一个对象,synchronized (this)用这个锁就能保证异步了,不会同步执行。 多写点多线程例子,就能很容易理解。
七月这天 2013-11-25
  • 打赏
  • 举报
回复
引用 13 楼 genganpeng 的回复:
[quote=引用 楼主 qiyuezhetian 的回复:]
public class EvenCheckerEasy implements Runnable {

	private static int val = 0;

	@Override
	public void run() {
		while (true) {
			++val;
			++val;
			System.out.println(val); // 在我电脑上测试,此处添加打印输出似乎防止了并发的产生,为什么?
			if (val % 2 != 0) {
				System.out.println(val + " not event!");
				return;
			}
		}
	}

	public static void main(String[] args) {
		ExecutorService exec = Executors.newCachedThreadPool();
		for (int i = 0; i < 10; i++) {
			exec.execute(new EvenCheckerEasy());
		}
		exec.shutdown();
	}
}
其实并没有阻止并发,将程序改成这样
private static int val = 0;
	private int i = 10;

	@Override
	public void run() {
		while (i-- > 0) {
			++val;
			++val;
			System.out.println(Thread.currentThread().getId() + ":" + val); // 在我电脑上测试,此处添加打印输出似乎防止了并发的产生,为什么?
			if (val % 2 != 0) {
				System.out.println(val + " not event!");
				return;
			}
		}
	}
得到的结果是 9:8 可以看出线程间还是交叉运行的,val++的操作都执行完了,我觉得可能是每个线程都在等待IO的调用,所以获得数都是偶数,这个应该跟线程与IO调用关系有关[/quote] 能说的更详细点吗?线程与IO调用有什么关系呢?
七月这天 2013-11-25
  • 打赏
  • 举报
回复
引用 12 楼 zxcvbnm11920 的回复:
又是一个讨论离题的帖子,查下源代码就知道原因了。

public void println(int x) {
	synchronized (this) {
	    print(x);
	    newLine();
	}
}
仓促就结贴了,细想下觉得还是不对,能解释的更详细点吗?
rumlee 2013-11-25
  • 打赏
  • 举报
回复
引用 17 楼 qiyuezhetian 的回复:
[quote=引用 12 楼 zxcvbnm11920 的回复:] 又是一个讨论离题的帖子,查下源代码就知道原因了。

public void println(int x) {
	synchronized (this) {
	    print(x);
	    newLine();
	}
}
要的就是你的答案![/quote] out对象加的同步锁与楼主描述的状况并无实际关联。
引用 13 楼 genganpeng 的回复:
[quote=引用 楼主 qiyuezhetian 的回复:]
public class EvenCheckerEasy implements Runnable {

	private static int val = 0;

	@Override
	public void run() {
		while (true) {
			++val;
			++val;
			System.out.println(val); // 在我电脑上测试,此处添加打印输出似乎防止了并发的产生,为什么?
			if (val % 2 != 0) {
				System.out.println(val + " not event!");
				return;
			}
		}
	}

	public static void main(String[] args) {
		ExecutorService exec = Executors.newCachedThreadPool();
		for (int i = 0; i < 10; i++) {
			exec.execute(new EvenCheckerEasy());
		}
		exec.shutdown();
	}
}
其实并没有阻止并发,将程序改成这样
private static int val = 0;
	private int i = 10;

	@Override
	public void run() {
		while (i-- > 0) {
			++val;
			++val;
			System.out.println(Thread.currentThread().getId() + ":" + val); // 在我电脑上测试,此处添加打印输出似乎防止了并发的产生,为什么?
			if (val % 2 != 0) {
				System.out.println(val + " not event!");
				return;
			}
		}
	}
得到的结果是 10:10 10:68 10:70 10:72 10:74 10:76 10:78 10:8 10:80 10:84 11:116 11:118 11:120 11:122 11:124 11:26 11:28 11:30 11:34 11:8 12:152 12:156 12:168 12:170 12:174 12:178 12:182 12:186 12:190 12:90 13:114 13:126 13:128 13:130 13:132 13:162 13:32 13:36 13:38 13:40 14:22 14:50 14:52 14:54 14:56 14:58 14:60 14:62 14:64 14:66 15:100 15:102 15:104 15:106 15:108 15:110 15:112 15:46 15:96 15:98 16:136 16:138 16:140 16:142 16:144 16:146 16:148 16:150 16:158 16:92 17:154 17:172 17:180 17:188 17:192 17:194 17:196 17:198 17:200 17:82 8:134 8:160 8:164 8:166 8:176 8:184 8:52 8:86 8:90 8:94 9:12 9:14 9:16 9:18 9:20 9:24 9:42 9:46 9:48 9:8 可以看出线程间还是交叉运行的,val++的操作都执行完了,我觉得可能是每个线程都在等待IO的调用,所以获得数都是偶数,这个应该跟线程与IO调用关系有关[/quote] 我认为13楼说的是对的。
七月这天 2013-11-25
  • 打赏
  • 举报
回复
引用 12 楼 zxcvbnm11920 的回复:
又是一个讨论离题的帖子,查下源代码就知道原因了。

public void println(int x) {
	synchronized (this) {
	    print(x);
	    newLine();
	}
}
要的就是你的答案!
七月这天 2013-11-25
  • 打赏
  • 举报
回复
引用 14 楼 taosheng2002 的回复:
Hi, 我做了个实验,我发现没有打印方法的代码更容易出现奇数退出程序。但并不是说有System的代码不会出现奇数。 请用调试模式启动System打印的代码,在not event处打上断点。立即会得到断点进入,并且完成线程退出。这可以说明这条语句没有造成妨碍并发,只是使得并发更难发生。至于为什么更难,我也不太清楚。
多线程不能用普通方式设置断点来调试吧!
七月这天 2013-11-25
  • 打赏
  • 举报
回复
引用 11 楼 rumlee 的回复:
[quote=引用 10 楼 qiyuezhetian 的回复:] [quote=引用 4 楼 rumlee 的回复:] 这里并非因为阻塞了,而是因为两个++val执行所需要的时间太小了,而造成了你的一种错觉。 你在++val中间加上一行try{ Thread.sleep(100); }catch(Exception e){} 很快你就会发现最终只有一个线程在跑了,其它9个都会在很短的时间内结束掉。
那还是不明白,其他的9个线程都结束了,为什么还有一个线程没有产生并发呢?[/quote] 一个线程何来并发?[/quote] 哦,可能我表述有问题,我的意思是为什么总有一个线程没有与其他线程之前产生并发。
七月这天 2013-11-24
  • 打赏
  • 举报
回复
引用 4 楼 rumlee 的回复:
这里并非因为阻塞了,而是因为两个++val执行所需要的时间太小了,而造成了你的一种错觉。 你在++val中间加上一行try{ Thread.sleep(100); }catch(Exception e){} 很快你就会发现最终只有一个线程在跑了,其它9个都会在很短的时间内结束掉。
那还是不明白,其他的9个线程都结束了,为什么还有一个线程没有产生并发呢?
zhuweisyyc 2013-11-24
  • 打赏
  • 举报
回复
引用 8 楼 rumlee 的回复:
[quote=引用 7 楼 waynexuan 的回复:] [quote=引用 6 楼 rumlee 的回复:] [quote=引用 5 楼 waynexuan 的回复:] [quote=引用 4 楼 rumlee 的回复:] 这里并非因为阻塞了,而是因为两个++val执行所需要的时间太小了,而造成了你的一种错觉。 你在++val中间加上一行try{ Thread.sleep(100); }catch(Exception e){} 很快你就会发现最终只有一个线程在跑了,其它9个都会在很短的时间内结束掉。
最好先试一下楼主的代码再说话[/quote] 你说了之后,我特意运行了一下,没有发现有阻塞啊。你所说的阻塞是在哪。[/quote] 把这句注释掉结果就不一样了 System.out.println(val); [/quote] 我还以为你们说的是什么。我第一个回复是没错的。并非是因为println阻塞,而是因为println所消耗的时间远远超过++val的时间,而造成的错觉。只需在两个++中间sleep一个时间段,就能够很轻易的看到效果了。[/quote] 可能是跟System.out 获得的流有关。
rumlee 2013-11-24
  • 打赏
  • 举报
回复
引用 7 楼 waynexuan 的回复:
[quote=引用 6 楼 rumlee 的回复:] [quote=引用 5 楼 waynexuan 的回复:] [quote=引用 4 楼 rumlee 的回复:] 这里并非因为阻塞了,而是因为两个++val执行所需要的时间太小了,而造成了你的一种错觉。 你在++val中间加上一行try{ Thread.sleep(100); }catch(Exception e){} 很快你就会发现最终只有一个线程在跑了,其它9个都会在很短的时间内结束掉。
最好先试一下楼主的代码再说话[/quote] 你说了之后,我特意运行了一下,没有发现有阻塞啊。你所说的阻塞是在哪。[/quote] 把这句注释掉结果就不一样了 System.out.println(val); [/quote] 我还以为你们说的是什么。我第一个回复是没错的。并非是因为println阻塞,而是因为println所消耗的时间远远超过++val的时间,而造成的错觉。只需在两个++中间sleep一个时间段,就能够很轻易的看到效果了。
WayneXuan 2013-11-24
  • 打赏
  • 举报
回复
引用 6 楼 rumlee 的回复:
[quote=引用 5 楼 waynexuan 的回复:] [quote=引用 4 楼 rumlee 的回复:] 这里并非因为阻塞了,而是因为两个++val执行所需要的时间太小了,而造成了你的一种错觉。 你在++val中间加上一行try{ Thread.sleep(100); }catch(Exception e){} 很快你就会发现最终只有一个线程在跑了,其它9个都会在很短的时间内结束掉。
最好先试一下楼主的代码再说话[/quote] 你说了之后,我特意运行了一下,没有发现有阻塞啊。你所说的阻塞是在哪。[/quote] 把这句注释掉结果就不一样了 System.out.println(val);
rumlee 2013-11-24
  • 打赏
  • 举报
回复
引用 5 楼 waynexuan 的回复:
[quote=引用 4 楼 rumlee 的回复:] 这里并非因为阻塞了,而是因为两个++val执行所需要的时间太小了,而造成了你的一种错觉。 你在++val中间加上一行try{ Thread.sleep(100); }catch(Exception e){} 很快你就会发现最终只有一个线程在跑了,其它9个都会在很短的时间内结束掉。
最好先试一下楼主的代码再说话[/quote] 你说了之后,我特意运行了一下,没有发现有阻塞啊。你所说的阻塞是在哪。
加载更多回复(5)

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧