在Java中使用notify时,thread和runnable之间有什么区别吗?

时间:2014-06-10 03:37:07

标签: java notify

当我尝试在Java中对 notify()进行一些测试时,我发现了一些困惑。

这里我有两个线程b1和b2,它们引用另一个线程a。在b1和b2中,它们将调用wait()。在线程a中,它将调用notify()。据我所知,它将再次调用b1或b2。当我用Runnable意识到这一点时,确实如此。但是当我使用Thread意识到这一点时,b1和b2都重新启动。任何人都能解释一下吗?

这是代码。

使用Runnable实现:

主题A:

public class threada implements Runnable{

    @Override
    public void run() {
        // TODO Auto-generated method stub
        String name = Thread.currentThread().getName();
        System.out.println(name+" started");
        synchronized(this){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(name + "end");
            notify();
        }
    }
}

主题B:

public class threadb implements Runnable{

    private threada ta;
    public threadb(threada a){
        ta = a;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        String name = Thread.currentThread().getName();
        System.out.println(name + " started");
        synchronized(ta){
            try {
                ta.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(name + "end");
        }
    }

}

主:

public class threadmain {
    public static void main(String...args){
        threada a = new threada();

        threadb b1 = new threadb(a);
        threadb b2 = new threadb(a);

        new Thread(b1, "b1").start();
        new Thread(b2, "b2").start();

        new Thread(a, "a").start();
    }
}

结果:

b1 started
a started
b2 started
aend
b1end

使用Thread实现:

主题A:

public class ThreadA extends Thread{

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        System.out.println(name+" started");
        synchronized(this){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(name + "end");
            notify();
        }
    }
}

主题B:

public class ThreadB extends Thread{

    private ThreadA ta;
    public ThreadB(ThreadA a){
        ta = a;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
//      super.run();
        String name = Thread.currentThread().getName();
        System.out.println(name + " started");
        synchronized(ta){
            try {
                ta.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(name + "end");
        }
    }
}

主要:

public class ThreadMain {
    public static void main(String... args) throws InterruptedException {
        ThreadA a = new ThreadA();

        ThreadB b1 = new ThreadB(a);
        ThreadB b2 = new ThreadB(a);
        b1.setName("b1");
        b2.setName("b2");

        b1.start();
        b2.start();

        Thread.sleep(10);

        a.setName("a");
        a.start();
    }
}

结果:

b1 started
b2 started
a started
aend
b1end
b2end

4 个答案:

答案 0 :(得分:1)

有趣的是,Thread.join()

记录了您的问题的解决方案
  

当一个线程终止时,调用this.notifyAll方法

所以你的一个线程被notify()调用唤醒,而另一个线程被线程A结束唤醒,从而在自身上发送notifyAll()。因此,每当线程死亡时,等待它的一切都会被唤醒。

Runnable版本没有发生这种情况,因为等待链接到Runnable对象而非线程。

答案 1 :(得分:-1)

无论如何,你必须以一种方式实现你的线程,如果调用notifyAll(),那么你的代码中就没有竞争条件或任何问题,比如死锁

并且根据经验,使用notifyAll()而不是notify()。

答案 2 :(得分:-1)

您的ThreadB没有对ThreadA实例的引用 - 您永远不会对其进行初始化。您必须将ThreadA实例传递给ThreadB实例,或者如果主代码具有该字段的可见性,您可以直接设置它。

另外,根据javadocs:

您似乎应该致电notifyAll()

答案 3 :(得分:-1)

notify是Object上的一个方法,它在所有对象上通常是相同的。您可以使用普通ObjectStringListbyte[],它会做同样的事情。注意:如果您打算使用notify,通常使用wait()而不是sleep(),因此通知会执行某些操作。

相关问题