这是我的代码:
public class ThreadDemo {
public static void main(String args[]) throws Exception {
Printer[] printers = new Printer[5];
printers[0] = new Printer("@base");
printers[1] = new Printer("#try");
printers[2] = new Printer("!test");
printers[3] = new Printer("^hello");
printers[4] = new Printer("*world");
for (Printer x : printers) {
x.start();
}
try {
for (Printer y : printers) {
y.join();
}
} catch (InterruptedException e) {
System.out.println(e);
}
}
}
class Printer extends Thread {
public Printer(String name) {
super(name);
}
public void run() {
print();
}
public synchronized void print() {
for (int i = 0; i < 10; i++) {
System.out.print(getName().charAt(0));
try {
sleep(100);
} catch (InterruptedException e) {
System.out.println(e + " occured");
}
}
}
}
它导致了
@^!#**@^!#*#@!^@*#^!#^!*@^*@!#@!#*^@#^!*!@^#*#@*^!
我的期望是所有符号将根据首先启动的线程序列化为@@@@@ ^^^^^。
调用sleep()会让其他线程继续进行直到当前线程的休眠时间,但我想不应该是同步方法的情况。
同步在这里不起作用。
该关键字确保您不能并行地在同一对象上调用相同的方法。
您正在不同的对象上调用它,因此即使没有关键字,结果也会相同!
(我宁愿假设您看到的结果实际上是由于在这里使用println()
引起的。这是一个“非常慢”的操作,当被超线程快速完成所有其他工作的线程使用时会引入“事实上的”同步。我是试图找到一些关于它的其他信息,但这可能需要更多时间)
你的代码或我的问题会说你的期望是方法print
在对象级别同步,你正在创建新的线程对象,启动线程并调用此方法。
因此,在这种情况下,每个方法在每个单独的线程对象上同步。为了实现您期望的行为,我们可以使print方法保持静态并查看行为更改。您将获得预期的结果,因为那时,方法print
在Printer
类锁的单个实例上同步。因此,即使不同的线程实例正在调用此方法,因为对于类只有一个锁,线程执行依次发生。
public static synchronized void print() {
for (int i = 0; i < 10; i++) {
System.out.print(Thread.currentThread().getName().charAt(0));
try {
sleep(100);
} catch (InterruptedException e) {
System.out.println(e + " occured");
}
}
}
@SolomonSlow - 所以必须纠正为'同步方法'可以同时在同一个对象上调用吗?
关于同步实例方法,您只需要知道一件事。你需要知道这......
synchronized void Foobar() { ... }
...只是编写同步块的快捷方式。
void Foobar() {
synchronized (this) {
...
}
}
这两个方法声明都完全相同。因此,您知道或了解同步块行为的所有内容也可以应用于同步方法。
关于synchronized
块的最重要的事情是,“没有两个线程可以同时在同一个对象上同步。”如果您了解这一点,并且如果您知道同步方法只是同步块的快捷方式,那么您可以回答自己的问题。