等待并通知所需的解释

时间:2014-01-06 13:44:00

标签: java multithreading thread-safety

我正在阅读并试图了解线程中的等待和通知机制。 为此,我需要清除我的概念,因此,只是确定我的概念,我在尝试的例子上提出问题,如下所示

请按照代码段

进行操作
class CodeOne implements Runnable{

    @Override
    public void run(){
        try{
            synchronized(this){
                for(int i=1;i<=5;i++){
                    System.out.println(Thread.currentThread().getName()+" : "+i);
                    Thread.sleep(500);
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

public class ThreadPractiseOne{ 

    public static void testOne() throws Exception{
        CodeOne code = new CodeOne();
        Thread t1 = new Thread(code,"THREAD-ONE");
        Thread t2 = new Thread(code,"THREAD-TWO");
        t1.start();
        t2.start();
    }

    public static void main(String[] args){
        try{
            testOne();
        }catch(Exception e){

        }
    }
}   

从上面的代码我们可以看到sunchronized块使用'this'作为参数。 它的目的是,在main方法中创建的线程获取对象CodeOne的锁定,因此只有一个线程能够访问它。

我的上述理解是否正确?

如果是,

比我想根据下面编写的代码再问一个问题,

public class MyThread extends Thread{

    public MyThread(String name){
        this.setName(name);
    }

    public int total;

    @Override
    public void run(){
        try{
            synchronized(this){
                System.out.print(" ");
                for(int num=1; num <= 3; num++){
                    total += num;
                    System.out.print("..");
                    Thread.sleep(1000);
                }
                System.out.println("\n");
                notify();
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

public class MainThread {

    public static void main(String [] args){
        MyThread t1 = new MyThread("ONE");

        try{
            t1.start();
            synchronized(t1){
                System.out.println(" Waiting for Thread ONE to complete ");
                t1.wait();
            }

            System.out.println(" TOTAL is  "+t1.total);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

从上面的代码我们可以在类MainThread的main方法中看到,我使用了synchronized块但是参数传递了i t1,即线程实例。

这是否意味着主线程获取't1'上的锁?

如果是,为什么?

如果我这样做

synchronized(new MainThread())

MainThread课程中,我得到了一个例外

java.lang.IllegalMonitorStateException

为什么?

顺便说一下第二个程序的输出

Waiting for Thread ONE to complete 
 ......
 TOTAL is  6

2 个答案:

答案 0 :(得分:1)

  

从上面的代码我们可以看到synchronized块使用'this'作为   论点。它的目的是,在主要创建的线程   方法获取对象CodeOne的锁定,因此只有一个线程   能够访问它。

一次只有一个线程能够访问在该对象上同步的synchronized块内的代码。

  

这是否意味着主线程获取't1'上的锁?

在此示例中,thist1碰巧引用了相同的MyThread对象。

  

在MainThread类中,我得到一个异常

您必须向我们展示实际导致此问题的代码,但您无法在尚未notify开启的对象上调用waitsynchronized

  

顺便说一下第二个程序的输出

这取决于竞争条件。这取决于Thread首先获取MyThread对象上的锁定。如果它是主线程,那么这就是你将获得的输出。如果它是另一个线程,那些线将被反转。


我在wait()notify()上没有看到任何问题,所以我只想提及已经作出一般性解释的Gray's answer


最后,不要在synchronized个对象上Thread。当他们所指的实际线程结束时,它们的行为与普通对象不同。

答案 1 :(得分:1)

  

在main方法中创建的线程获取对象CodeOne的锁定,因此只有一个线程能够访问它。

是的,这是正确的。认识到它们锁定CodeOne的相同实例非常重要。只有在同一对象实例上有多个线程为synchronized时,锁才有效。

  

这是否意味着主线程获取't1'上的锁?

是。主线程和分叉线程都锁定在同一个Thread实例上。另外,将您的课程定义为implements Runnable而不是扩展Thread被认为是更好的模式。例如,Thread代码的其他部分锁定在Thread实例上。因为你锁定它也可能会导致一些意想不到的后果。

同样重要的是要意识到只是调用notify();是一种糟糕的模式。你应该明确地说this.notify();。他们做同样的事情,但它应该在synchronized (this) { ... this.notify(); }之间具有平价。

  

这是否意味着主线程获取't1'上的锁?

是。主线程锁定t1并且在this锁定的线程内部。所以他们锁定在同一个对象实例上。我不知道如何回答“为什么”这个问题。

  

java.lang.IllegalMonitorStateException

如果您尝试wait()notify()而不在synchronized区域内,则会发生这种情况。如果您说:

synchronized(new MainThread()) {
    ...
    notify();
}

然后,您正在同步一个对象,并尝试在不同的对象上通知您尚未锁定。锁对象通常应该是由多个线程共享的private final对象实例。做synchronized (new ...)之类的事情实际上从来都不是一个好模式。