简体   繁体   English

在Java中使用notify时,线程和可运行之间有什么区别吗?

[英]Is there any difference between thread and runnable when using notify in Java?

When I try to do some test about notify() in Java, I found some confusion. 当我尝试对Java中的notify()进行测试时,发现有些困惑。

Here I have two thread b1 and b2, they have the reference to another thread a. 在这里,我有两个线程b1和b2,它们引用了另一个线程a。 In b1 and b2, they will call wait(). 在b1和b2中,它们将调用wait()。 And in thread a, it will call notify(). 在线程a中,它将调用notify()。 As I know, it will call b1 or b2 to start again. 据我所知,它将调用b1或b2重新开始。 It is true when I realize this using Runnable. 当我使用Runnable实现这一点时,确实如此。 But when I realize this using Thread, b1 and b2 both start again. 但是当我使用Thread意识到这一点时,b1和b2都重新开始。 Can any one explain this? 有人可以解释吗?

Here is the code. 这是代码。

Realized using Runnable: 使用Runnable实现:

Thread A: 线程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();
        }
    }
}

Thread B: 线程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");
        }
    }

}

Main: 主要:

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();
    }
}

The Result: 结果:

b1 started
a started
b2 started
aend
b1end

Realized using Thread: 使用线程实现:

Thread A: 线程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();
        }
    }
}

Thread B: 线程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");
        }
    }
}

Main : 主要:

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();
    }
}

The result: 结果:

b1 started
b2 started
a started
aend
b1end
b2end

Interestingly the the solution to your question is documented for Thread.join() 有趣的是,您的问题的解决方案记录在Thread.join()中。

As a thread terminates the this.notifyAll method is invoked 当线程终止时,this.notifyAll方法被调用

So one of your threads was awoken by the notify() call and the other by the thread A ending and thus sending a notifyAll() on itself. 因此,您的一个线程被notify()调用唤醒,另一个线程被线程A结尾唤醒,因此自身发送了notifyAll() So every time a thread dies everything waiting on it will awaken. 因此,每次线程死亡时,等待它的所有事物都会唤醒。

This didn't happen for the Runnable version as the wait was linked to the Runnable objects and not the Thread. 对于Runnable版本,这没有发生,因为等待已链接到Runnable对象而不是Thread。

At any rate, you have to implement your threads in a way where if notifyAll() get called then there will be no race condition or any problems in your code such as deadlock 无论如何,您必须以某种方式实现线程,如果调用notifyAll(),则不会出现竞争状况或代码中的任何问题(例如死锁)

and as a rule of thumb, use notifyAll() instead of notify(). 根据经验,请使用notifyAll()而不是notify()。

Your ThreadB does not have a reference to the ThreadA instance - you never initialize it. 您的ThreadB没有对ThreadA实例的引用-您永远不会初始化它。 You must pass the ThreadA instance to the ThreadB instances, or if the main code has visibility of the field, you can set it directly. 您必须将ThreadA实例传递给ThreadB实例,或者如果主代码具有该字段的可见性,则可以直接对其进行设置。

Also, as per the javadocs: 另外,按照javadocs:

It seems you should be calling notifyAll() . 看来您应该调用notifyAll()

notify is a method on Object which is generally the same on all objects. notify是Object上的一种方法,通常在所有对象上都是相同的。 You could use a plain Object or a String or List or byte[] and it would do the same thing. 您可以使用一个普通的ObjectStringListbyte[] ,它会做同样的事情。 Note: if you are going to use notify, you generally use wait() instead of sleep() so the notify does something. 注意:如果要使用notify,则通常使用wait()而不是sleep(),因此notify会执行某些操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Java通知AWT调度线程何时已执行可运行 - Java notify when AWT dispatching thread has executed runnable JAVA Runnable class 启动线程有什么区别? - What is the difference between JAVA Runnable class to start thread? 使用Runnable和Thread创建线程的区别? - Difference in creation of thread using Runnable and Thread? ThreadPool中的Runnable与Thread和ThreadPool中的Runnable有什么区别 - What is Difference between Runnable in a ThreadPool vs Runnable inside a Thread and in a ThreadPool 在使用Runnable的线程和派生的Thread类之间发生行为方面的意外差异 - Unexpected difference in behaviour between using a thread using a Runnable and a derived Thread class 在实现Runnable的Java中使用线程时形状未移动 - The shape is not moving when using thread in java implementing runnable 使用 Thread 和 Runnable 时,Lambba 在 Java 中如何工作? - How do Lambba works in Java when using Thread and Runnable? Java中Runnable和Callable接口的区别 - The difference between the Runnable and Callable interfaces in Java new Thread(Runnable object).start() 与 new Thread(Runnable ref. {run()});.start() 之间的区别 - DIfference between new Thread(Runnable object).start() vs. new Thread(Runnable ref. {run()});.start() 使用Runnable或Thread出现Java线程问题 - Issue with Java threads, using Runnable or Thread
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM