我有一个关于线程的问题。我有跟随Thread类并创建2个线程对象。
public class MyThread extends Thread{
String name="";
public MyThread(String string) {
name=string;
}
@Override
public void run() {
callMe();
}
synchronized private void callMe() {
System.out.println("Started");
for (int i = 1; i <= 5; i++) {
System.out.println(name+" = "+i);
}
}
public static void main(String[] args) {
MyThread a = new MyThread("A");
MyThread b = new MyThread("B");
a.start();
b.start();
}
}
当我执行此操作时,我得到的输出是 -
Started
Started
B = 1
B = 2
A = 1
A = 2
B = 3
A = 3
B = 4
A = 4
B = 5
A = 5
我知道当线程安排程序选择它时,A和B会随机打印。
但我的问题是:为什么循环不会一个接一个地执行?我使用了synchronized
关键字。
答案 0 :(得分:13)
您的synchronized
方法实际上是:
private void callMe() {
synchronized(this) {
System.out.println("Started");
for (int i = 1; i <= 5; i++) {
System.out.println(name+" = "+i);
}
}
}
现在你已经创建了两个不同的实例,因此this
对于每个线程都是不同的......因此它们不会相互同步。如果你想看到两个线程使用相同的监视器,你可以像这样重写你的代码:
public final class DemoRunnable implements Runnable {
@Override
public synchronized void run() {
System.out.println("Started");
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + " = " + i);
}
}
public static void main(String[] args) {
Runnable runnable = new DemoRunnable();
Thread a = new Thread(runnable, "A");
Thread b = new Thread(runnable, "B");
a.start();
b.start();
}
}
然后你会得到这样的输出:
Started
A = 1
A = 2
A = 3
A = 4
A = 5
Started
B = 1
B = 2
B = 3
B = 4
B = 5
(当然,这可能是相反的方式。)
我们仍然有两个线程,但他们在同一个对象上调用一个synchronized方法(在这种情况下为DemoRunnable
),因此必须等待另一个完成。
几点:
Runnable
通常比扩展Thread
更受欢迎;它更灵活Thread
对象有其自身的问题,因为Thread
类本身就是这样做的;尽量避免它this
上进行同步 - 我通常会有一个Object
类型的私有最终变量来表示我的代码只知道 的监视器...这样我就可以很容易地看到所有可以在其上同步的代码,这样可以更容易推理答案 1 :(得分:9)
每个对象同步工作。要跨实例进行同步,您需要一个共享对象来进行同步。
即
private final static Object globalLock = new Object();
// Later
private void callMe() {
synchronized (globalLock) {
System.out.println("Started");
for (int i = 1; i <= 5; i++) {
System.out.println(name+" = "+i);
}
}
}
答案 2 :(得分:3)
您的准则与本准则相同
private void callMe(){
synchronized(this){
System.out.println("Started");
for (int i = 1; i <= 5; i++) {
System.out.println(name+" = "+i);
}
}
}
您只需与当前对象同步即可。 如果要将它们彼此同步,则需要同步到类, 像这样:
private void callMe(){
synchronized(MyThread.class){
System.out.println("Started");
for (int i = 1; i <= 5; i++) {
System.out.println(name+" = "+i);
}
}
}
答案 3 :(得分:2)
因为2个线程正在通过2个不同的对象执行。
好吧,你现在必须从其他答案中实现。您正在创建2个单独的对象,即。 a和b。现在,当您调用start方法时,将启动一个新线程,以通过相应(单独的不相同)对象的run方法执行。同步确实在方法上,但是只有一个线程在a的callMe方法中运行,而正好一个线程在b的callMe方法中运行。所以你期望输出应该是:
A - 1 A2 A - 3 ...
没有发生。
希望这有帮助