方法 synchronized ,但代码由于非序列化线程行为而产生随机结果
Method synchronized , but code produces random result due to non-serialized thread behaviour
这是我的代码:
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() 会让其他线程继续执行直到当前线程的睡眠时间,但我想同步方法不应该是这种情况。
你的代码有问题或者我会说你的期望是方法 print
在对象级别同步并且你正在创建新的线程对象,启动线程并调用此方法。
所以在这种情况下,每个方法都在每个单独的线程对象上同步。为实现您期望的行为,我们可以将 print 方法设为静态并查看行为变化。您将获得预期的结果,因为那样的话,方法 print
在 Printer
class 锁的单个实例上同步。因此,即使不同的线程实例正在调用此方法,因为 class 有一个锁,线程执行顺序发生。
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");
}
}
}
同步在这里没有发挥作用。
该关键字确保您不能在 same 对象上并行调用 same 方法。
你在不同的对象上调用它,因此即使没有关键字,结果也是一样的!
( 我宁愿 假设 你看到的结果实际上是由这里使用 println()
引起的。那是一个 "really slow" 操作,它引入了 "de facto" 由超快速完成所有其他工作的线程使用时的同步。我正在尝试找到一些关于它的额外信息,但这可能需要更多时间)
@SolomonSlow - So it has to be corrected as 'No Synchronized methods' can be called on the same object at same time ?
关于同步实例方法,您只需要了解一件事。你需要知道这...
synchronized void Foobar() { ... }
...只是一个写同步块的捷径
void Foobar() {
synchronized (this) {
...
}
}
这两个方法声明完全做同样的事情。因此,您所知道或了解的有关同步块如何运行的所有内容也可以应用于同步方法。
关于 synchronized
块最重要的是,"No two threads can ever be synchronized on the same object at the same time." 如果您了解这一点,并且如果您知道同步方法只是同步块的快捷方式,那么您可以回答你自己的问题。
这是我的代码:
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() 会让其他线程继续执行直到当前线程的睡眠时间,但我想同步方法不应该是这种情况。
你的代码有问题或者我会说你的期望是方法 print
在对象级别同步并且你正在创建新的线程对象,启动线程并调用此方法。
所以在这种情况下,每个方法都在每个单独的线程对象上同步。为实现您期望的行为,我们可以将 print 方法设为静态并查看行为变化。您将获得预期的结果,因为那样的话,方法 print
在 Printer
class 锁的单个实例上同步。因此,即使不同的线程实例正在调用此方法,因为 class 有一个锁,线程执行顺序发生。
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");
}
}
}
同步在这里没有发挥作用。
该关键字确保您不能在 same 对象上并行调用 same 方法。
你在不同的对象上调用它,因此即使没有关键字,结果也是一样的!
( 我宁愿 假设 你看到的结果实际上是由这里使用 println()
引起的。那是一个 "really slow" 操作,它引入了 "de facto" 由超快速完成所有其他工作的线程使用时的同步。我正在尝试找到一些关于它的额外信息,但这可能需要更多时间)
@SolomonSlow - So it has to be corrected as 'No Synchronized methods' can be called on the same object at same time ?
关于同步实例方法,您只需要了解一件事。你需要知道这...
synchronized void Foobar() { ... }
...只是一个写同步块的捷径
void Foobar() {
synchronized (this) {
...
}
}
这两个方法声明完全做同样的事情。因此,您所知道或了解的有关同步块如何运行的所有内容也可以应用于同步方法。
关于 synchronized
块最重要的是,"No two threads can ever be synchronized on the same object at the same time." 如果您了解这一点,并且如果您知道同步方法只是同步块的快捷方式,那么您可以回答你自己的问题。