java中的synchronized关键字

时间:2017-09-02 19:04:43

标签: java multithreading synchronization

我从A类创建了一个扩展Thread类的两个线程a1a2。 A类声明两个构造函数并运行同步的方法。当我以这种形式编写代码时,虽然run方法被声明为synchronized并且我得到的结果像

,但有时两个线程同时启动
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 

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

3 个答案:

答案 0 :(得分:1)

当您通过在某个时刻调用start()来运行线程时,它会调用run()Thread类中的public void run() { if (target != null) { target.run(); } } 方法:

run

此代码负责执行Runnable target构造函数中传递的new Thread(Runnable target)对象Thread#run()方法的代码。

但是你在A课程中覆盖了start()。所以现在A#run方法调用target.run()(因为多态),这意味着它永远不会调用t.run()(在您的情况下 - t,因为A被传递为{ {1}}线程目标)。
现在即使A#run方法是synchronized,因为每个线程在单独的实例(线程对象本身)上调用它,所以没有发生同步,因为线程没有使用 common lock / monitor。

您只能获得正确的结果,因为有时一个线程能够在其他线程开始之前完成其全部工作。

为了避免这种令人困惑的问题(以及许多其他问题)根本不扩展线程。创建实现Runnable的类并将其传递给Thread实例。

Runnable视为任务,将Thread视为应该执行该任务的 worker 。你的工作是描述 工作者应该做什么(拿走它,把它放在那里),而不是如何(弯曲你的膝盖,抓住它,......)。

答案 1 :(得分:0)

除非您使用SemaphoreCountDownLatchCyclicBarrier等同步器,否则您无法确定线程是否同时启动。 synchronized关键字本身用于保护相同对象(方法或代码块)免受并发访问。在您的代码synchronized中没用。

答案 2 :(得分: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
    
  5. 我刚刚展示了基本的锁定机制。对于多线程的高级版本,您可以参考high level concurrency教程。