2017-09-02 37 views
0

我从扩展Thread类的类A创建了两个线程a1a2。类A声明了两个同步的构造函数和run方法。当我以这种形式编写的代码两个线程有​​时开始在同一时间虽然run方法声明为synchronized和我得到的结果一样java中的同步关键字

0 0 1 1 2 3 4 5 6 7 2 8 3 9 4 10 5 11 6 12 7 8 9 10 11 12 

代码:

public class Main { 
    public static void main(String[] args) {  
     A t = new A() ;  
     A a1 = new A (t) ;  
     A a2 = new A (t) ; 

     a1.start(); 
     a2.start(); 
    }  
} 

class A extends Thread { 
    public A() { 
     super() ; 
    } 

    public A(Thread th) { 
     super(th) ; 
    } 
    @Override 
    public synchronized void run() { 
     for (int i = 0; i <13; i++) { 
      System.out.print(i+" ");    
     }  
    } 
} 

但是,当我通过创建Thread类不是A两个线程,

Thread a1 = new Thread (t); 
Thread a2 = new Thread (t); 

同步方法run工作,两个线程不会在开始同时总是给结果

0 1 2 3 4 5 6 7 8 9 10 11 12 0 1 2 3 4 5 6 7 8 9 10 11 12 

我的问题:为什么synchronized关键字,当我创建A级两个线程(虽然我定义了两个构造函数)不工作,工作时,我创建Thraed类两个线程?

+2

您如何看到第一种情况下的线程在同一时间开始?你看到混合输出吗?你能告诉我们那个输出吗? –

+1

我可以向你保证'synchronized'确实能正常工作。你正在同步线程对象本身,这真的有点没有意义。 –

+0

我的朋友同步始终正常工作。现在你的错误是在这里理解**线程a1 =新线程(t);线程a2 =新的线程(t); **小的描述=在这里你创建两个不同的对象有两个不同的锁权利?所以为什么一个线程会等待你有这个?两个线程都有不同的锁定。得到它了? –

回答

1

当您在某些时候调用start()运行的线程将调用其run()方法,在Thread类看起来是这样的:

public void run() { 
    if (target != null) { 
     target.run(); 
    } 
} 

此代码是负责从Runnable target对象run方法new Thread(Runnable target)通过执行代码构造函数。

但是你在A课程中覆盖了Thread#run()。所以,现在start()方法调用A#run(因为多态性),这意味着它永远不会调用target.run()(在你的情况 - t.run()因为t是为A线体通过)。
现在,即使A#run方法是​​,因为每个线程都在单独的实例(线程对象本身)上调用它,所以不会发生同步,因为线程不使用常见的锁定/监视器。

由于有时候一个线程能够在其他启动之前完成其全部工作,因此您会获得正确的结果。


为了避免这样的混乱问题(和许多其他)在所有没有扩展Thread。创建实现Runnable的类并将其传递给Thread实例。

想想Runnable任务,并Thread工人应该执行该任务。你的工作是描述什么工人应该做的(拿这个,把它放在那里),而不是如何(弯曲你的膝盖,抓住,..)。

+0

非常感谢您的回答 –

0

除非使用同步器,如Semaphore,CountDownLatchCyclicBarrier,否则无法确定线程是否同时启动。 ​​关键字本身用于保护相同的对象(方法或代码块)免于并发访问。在你的代码​​是无用的。

0

下面是修改后的代码来处理您的问题。

public class RunnableDemo { 
    public static void main(String[] args) {  

     Object lock = new Object(); 
     Thread t1 = new Thread (new MyRunnable(lock));  
     Thread t2 = new Thread (new MyRunnable(lock));  

     t1.start(); 
     t2.start(); 
    }  
} 

class MyRunnable implements Runnable { 
    Object lock = new Object(); 
    public MyRunnable(Object lock){ 
     this.lock = lock; 
    } 

    @Override 
    public void run() { 
     synchronized(lock){ 
      for (int i = 0; i <13; i++) { 
       System.out.print(i+" ");    
      } 
     }   
    } 
} 
  1. 共享锁在主类中创建:RunnableDemo
  2. 两个线程已经通过传递MyRunnable对象,它实现接口Runnable创建。代替扩展Thread以创建新的Thread,将Runnable接口实现传递给Thread构造函数是首选方法。
  3. 两个线程都已启动。因为他们有着共同的锁,只有一个Thread完整run()
  4. 现在你可以看到输出是如下正确的顺序:

    0 1 2 3 4 5 6 7 8 9 10 11 12 0 1 2 3 4 5 6 7 8 9 10 11 12 
    

我刚刚展示了基本的锁定机制。对于高级版本的多线程,您可以参考high level concurrency教程。