同步线程方法正在并发执行 - 为什么?

问题描述:

我有一个关于线程的问题。我有以下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是随机打印。

但我的问题是:为什么循环不是一个接一个地执行?我已使用​​关键字。

你​​方法是有效的:

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 

(虽然它可以)

我们仍然有两个线程,但他们在同一个对象上调用同步方法(在这种情况下为DemoRunnable),所以必须等待另一个线程完成。

的几点:

  • 实施Runnable通常优于延伸Thread;它更灵活
  • Thread对象上同步有其自身的问题,因为Thread类自己做;尽量避免它
  • 我个人不喜欢this同步反正 - 我通常会对Object类型的私人最终变量来表示只有我的代码知道...这样,我可以很容易地看到显示器所有,可以在其上同步的代码,这使得它更容易推理
+0

因此,在你的第一个代码片段中,它不会保持Synchronized'method'正确吗?它变成Synchronized'语句'。第二个代码片段就是Synchronized'method'的一个例子,对吗? – 2014-10-08 11:36:52

+0

@NinadPingale:是的,但这种差异实际上是不相关的 - “同步”方法实际上是一个包含方法体的'synchronized(this)'语句的普通方法。 (例如方法;对于静态方法,它在'Class'对象上同步。) – 2014-10-08 11:38:16

为每个对象同步的作品。要跨实例进行同步,您需要共享对象才能进行同步。

I.e.

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); 
    } 
    } 
} 
+0

globalLock必须强制static..otherwise它doen't工作的权利? – 2014-10-08 11:25:32

+1

使用静态对象(而不是实例对象)的原因是,每个实例都在同一个对象上进行同步。我建议将'globalLock'声明为'private'和'final'。 – Brian 2014-10-08 15:46:24

+0

@Brian Yeah这是一个好主意,从我这里更新了答案 – jontro 2014-10-08 16:21:10

因为2个线程正在通过2个不同的对象执行。

好吧,您现在必须从其他答案中实现。您正在创建2个独立的对象,即。 a和b。现在,当您调用start方法时,将启动一个新线程,通过相应(单独不相同)对象的run方法执行。同步确实在该方法上,但恰好有一个线程通过a的callMe方法运行,恰好有一个线程通过b的callMe方法运行。所以,你的期望输出应该是:

A - 1 A - 2 A - 3 ...

没有发生。

希望这有助于

+0

-1 - 这是一个非常简洁的答案。没有足够的信息来解释问题发生的原因。 – 2014-10-08 11:02:36

+0

好的,好吧,我会详细说明:) – Ironluca 2014-10-08 11:04:18

代码等于本守则

private void callMe(){ 
     synchronized(this){ 
      System.out.println("Started"); 
      for (int i = 1; i <= 5; i++) { 
       System.out.println(name+" = "+i); 
      } 
     }       
} 

您只需S与当前对象同步。 如果你想将它们彼此同步您的需要同步到类, 这样的:

private void callMe(){ 
    synchronized(MyThread.class){ 
    System.out.println("Started"); 
    for (int i = 1; i <= 5; i++) { 
      System.out.println(name+" = "+i); 
    } 
    } 
}