我正在阅读一本关于线程/同步的简单示例,该书声称使用synchronized
将允许在同一个实例上调用一个线程来访问该方法。它确实按照承诺进行了序列化,但似乎在下面的Caller
Synch
方法中创建的第三个main
约为9/10倍。此代码是示例代码,显示没有同步方法的问题。
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) {...} }
很明显,这两个选项都有效,因为与原始代码相反,括号内的单词是一致的......
[你好]
[世界](大约90%的时间是呼叫倒退)
[已同步](1 /多个已同步为第一个消息)
......原始代码没有押韵或理由。所以我知道它“正在工作”,可以通过在每个Caller
实例上放置断点来直接看到它。当我这样做时,它显然对我来说很有效。
为什么第三个Caller
在第二个call
之前一直在调用{{1}}?
答案 0 :(得分:4)
根据定义,线程并行运行,并且没有一个优先于任何其他线程。
一旦线程全部启动,它基本上是随机的,它将首先运行,一般来说,第一个启动将有一个轻微的“先发制人”,但与启动线程等的开销相比,先行开始很小。
你的特定环境的怪癖恰好偏向于一个线程,结果可能在不同的系统上有所不同,当然不应该依赖。
顺便提一下,这是不好的做法,原因有很多:
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();
这绝对可以确保Caller对象在Thread开始处理之前已完全初始化并准备就绪。
答案 1 :(得分:4)
为什么第三个呼叫在第二个呼叫之前一直呼叫呼叫?
它并没有这么做 - 它大约90%的时间都在这样做。
基本上,同步不能保证先进先出......并且无法保证呼叫甚至会按照您期望的顺序进行。三个新线程正在快速连续启动 - 没有保证哪个线程将首先实际开始执行其代码。
从根本上说,如果要对并行代码进行排序,则需要明确地这样做。同步不提供排序 - 它只提供排他性。
答案 2 :(得分:1)
它确实按照承诺进行了序列化,但似乎在下面的Synch主方法中创建的第三个Caller大约9/10倍出现在第二个之前。
小心理解句子中“序列化”的含义:它表示受同一锁保护的所有代码段永远不会并行运行;换句话说,它们的执行将是 serial 。
不的含义是“执行这些代码段将以严格的指定顺序执行”。它不会。