我正在阅读一本关于线程/同步的简单示例,该书声称使用synchronized会允许在同一实例上调用一个线程来访问该方法。它确实按照承诺进行了序列化,但似乎Caller在Synch main下面的方法中创建的第三个数组的大约9/10倍于第二个数组。该代码是示例代码,显示了没有同步方法的问题。
synchronized
Caller
Synch
main
class CallMe { void call(String msg) { System.out.print("[" + msg); try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("CallMe Interrupted"); } System.out.println("]"); } } class Caller implements Runnable { String msg; CallMe target; Thread t; public Caller (CallMe target, String msg) { this.target = target; this.msg = msg; t = new Thread(this); t.start(); } @Override public void run() { target.call(msg); } } class Synch { public static void main(String args[]) { CallMe target = new CallMe(); Caller c1 = new Caller(target, "Hello"); Caller c2 = new Caller(target, "Synchronized"); Caller c3 = new Caller(target, "World"); try { c1.t.join(); c2.t.join(); c3.t.join(); } catch (InterruptedException e) { System.out.println("Synch Interrupted"); } } }
这本书说明了两种方式来处理这个问题,他们是- synchronized void call(String msg) {...}并且 public void run() { synchronized (target) {...} }
synchronized void call(String msg) {...}
public void run() { synchronized (target) {...} }
很显然,这两种选择工作,因为,相对于原来的代码,括号内的字都像一致…
[您好] [世界](大约90%的电话回退时间) [已同步](1 /许多已同步为第一个味精)
…原始代码没有韵律或理由。因此,我知道它是“有效的”,可以通过在每个Caller实例上放置断点直接看到它。每当我这样做时,对我来说,它每次都有效。
为什么第三个在第二个之前Caller始终调用call?
call
根据定义,线程是并行运行的,并且没有任何优先级高于其他线程。
一旦线程全部启动,本质上是随机的,它将首先运行,通常,第一个启动的线程将具有轻微的“领先优势”,但是与启动线程等的开销相比,该优势很小。
您的特定环境的怪癖恰好偏向于使用一个线程,结果在不同的系统上可能会有所不同,因此当然不应该依赖它。
顺便说一句,这是不好的做法,原因有很多:
public Caller (CallMe target, String msg) { this.target = target; this.msg = msg; t = new Thread(this); t.start(); }
(实际上您可能会收到编译器警告)。
更好的是提供一种启动方法
public Caller start() { t.start(); return this; }
然后做
new Caller(target, msg).start();
这绝对可以确保Thread对象开始处理之前,Caller对象已完全初始化并准备就绪。