如何通过Java通知特定的线程

时间:2017-04-08 02:02:15

标签: java multithreading ipc java-threads

如何在线程间通信中调用特定线程?

在下面的程序中,我有两个帖子t1t2

当我致电t1.notify()时,它会加注:

Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at Shared.methodTwo(NotifyThread.java:43)
    at Thread2.run(NotifyThread.java:77)
Error 
class Shared {

    Thread1 t1 ;
    Thread2 t2 ;

    void ThreadInit( Thread1 t1 , Thread2 t2 ) {
        this.t1 = t1 ;
        this.t2 = t2 ;
    }

    synchronized void methodOne()
    {
        Thread t = Thread.currentThread();

        System.out.println(t.getName()+" is relasing the lock and going to wait");

        try
        {
            wait();        //releases the lock of this object and waits
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }

        System.out.println(t.getName()+" got the object lock back and can continue with it's execution");
    }

    synchronized void methodTwo()
    {
        Thread t = Thread.currentThread();

        try
        {
            Thread.sleep(5000);
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }

        t1.notify();     

        System.out.println("A thread which is waiting for lock of this object is notified by "+t.getName());
    }
    }

    class Thread1 extends Thread 
    {
    Shared s ;
    Thread1( Shared s ) {

        this.s = s ;
    }

    public void run()
            {
                s.methodOne();   //t1 calling methodOne() of 's' object
            }

    } 

    class Thread2 extends Thread {
         Shared s ;
    Thread2( Shared s ) {

        this.s = s ;

    }

    public void run()
            {
                s.methodTwo();   //t1 calling methodOne() of 's' object
            }


    }
    public class NotifyThread 
    {
    public static void main(String[] args)
    {
        final Shared s = new Shared();

        Thread1 t1 = new Thread1(s) ;
        Thread2 t2 = new Thread2(s) ;

        s.ThreadInit(t1,t2) ;

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

4 个答案:

答案 0 :(得分:5)

您不能/无法通知特定主题。您在锁定对象上调用notify()。这会唤醒等待锁定的其中一个 1 线程。在您的情况下,锁定对象是Thread ...这相当混淆了图片。但是,见下文。

但是你的问题(IllegalMonitorStateException)发生了,因为执行通知的线程(即当前线程)没有持有锁。 (硬)要求当前线程在通知锁时必须保持锁定。

有关详细信息,请阅读Object.wait(timeout)的javadoc或(例如):http://howtodoinjava.com/core-java/multi-threading/how-to-work-with-wait-notify-and-notifyall-in-java/

1 - 如果多个线程在等待你的锁,则选择一个线程"随机"由调度程序。或者,notifyAll将唤醒所有等待的线程。

我不会使用Thread对象作为锁定对象。它可能会工作,但也有可能其他东西(可能是运行时系统中的某些东西)也锁定/等待/通知Thread对象。然后事情会变得非常混乱。

(的确,请阅读Thread.join(long)的{​​{3}}!)

专门为此目的创建锁定对象更好; e.g。

private final Object lock = new Object();

另外,编写扩展Thread的类通常是个坏主意。通常最好实现Runnable接口,实例化它,并将实例作为参数传递给Thread构造函数; e.g。

Thread t = new Thread(new Runnable() {
    public void run() {
        System.out.println("Hello world");
    }});
t.start();

实现Runnable而不是扩展Thread的一个好处是,您可以更轻松地使用代码来管理线程生命周期;例如ExecutorService,fork-join线程池或经典线程池。

第二个是轻量级线程逻辑可以简洁地实现为匿名类......就像在我的例子中一样。

答案 1 :(得分:1)

添加一些要点;

您的代码使用的是内部锁。 JVM中的每个对象都有自己的锁。 此锁与对象的功能无关。获取锁本身没有任何作用(在没有使用synchronized关键字的其他措施的情况下)以防止其他线程使用对象的内容进行编码。在线程上调用notify并不意味着该特定线程将收到通知。

如前所述,不建议获取Thread对象的锁定。 Thread上的join方法使用连接到的线程上的内部锁。如果代码因不同原因获取锁定,则可以通知线程某些可能不关心的情况。

本机锁是一种中介,它告诉OS调度程序哪些线程正在等待。 OS调度程序决定通知锁的等待集中的哪些线程。当一个线程调用一个对象上的notify时,它告诉该对象的锁定告诉调度程序选择通知哪个等待线程。锁知道哪些线程在等待,但它不知道它们正在等待什么条件。 (ReentrantLock是一个很大的改进,请参阅条件的API文档。)

当然,notifyAll会唤醒等待集中的所有线程,但这又是锁和调度程序知道的内容。调用notifyAll的线程不知道正在等待的线程。系统是故意设计的,因此线程不能直接通知其他线程。

另一件事是调用wait而不检查条件是不可靠的。如果某个线程在发出通知之前没有碰巧获得锁定,则会错过该通知。如果一个线程收到一个通知,这不能保证它会获得下一个锁,另一个线程可能会动作并使通知线程所期望的状态无效。总是有一些内部状态,当前线程可以检查以验证对象的状态是线程期望的状态,并将该检查作为循环中的测试。

例如,如果我有一个固定大小的阻塞队列(在内部使用列表实现,保护它不使用同步进行并发访问),其中线程尝试从队列中获取某些内容但在队列为空时阻塞,则take方法可能看起来如此像:

public synchronized T take() throws InterruptedException {
    while (list.isEmpty()) {
        wait();
    }
    notifyAll();
    return list.remove(0);
}

等待线程唤醒并重新获取锁定后,它会检查当前情况是否等待它。只有在这种情况下,线程才会退出循环并继续。

答案 2 :(得分:0)

在这里您可以找到一个很好的示例,如何使用wait和notify或notifyAll()– Niraj 2天前
如果您使用notify()而不是notifyAll(),它将仅触发具有高优先级的wait()状态的一个线程。如果使用notifyAll(),它将触发所有处于wait()状态的线程。

   package com.construction.house;

import com.construction.labours.LabourCement;
import com.construction.labours.LabourPainting;
import com.construction.labours.LabourPolishMarbel;

public class House implements Runnable{

    public House() {
        // TODO Auto-generated constructor stub
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        House myHouse = new House();
        LabourCement labourCement = new LabourCement(myHouse,"Cement");
        labourCement.start();

        LabourPainting labourPaining = new LabourPainting(myHouse,"Painter");
        labourPaining.start();

        LabourPolishMarbel labourPolish = new LabourPolishMarbel(myHouse,"PolishMan");
        labourPolish.start();

    }
    boolean isPolished = false,isCemented = false,isPaited = false;

    public synchronized void workAsDemand() throws InterruptedException {
        if (!isPolished) {
            isPolished = true;
            System.out.println(Thread.currentThread().getName()+"--->>Polish in progress");
            wait();
            System.out.println(Thread.currentThread().getName()+"--->>Polish Completed");

        }

        else if (!isPaited) {
            System.out.println(Thread.currentThread().getName()+"--->>Painting house in Progress");
            isPaited = true;
            //notify();
            wait();
            System.out.println(Thread.currentThread().getName()+"--->>Painting house in Completed");

        }

        else if (!isCemented) {
            System.out.println(Thread.currentThread().getName()+"---->>Cemented house");
            isCemented = true;
            notifyAll();

        }


    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        try {
            workAsDemand();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}



package com.construction.labours;

public class LabourCement extends Thread {

    public LabourCement() {
        // TODO Auto-generated constructor stub
    }

    public LabourCement(Runnable arg0) {
        super(arg0);
        // TODO Auto-generated constructor stub
    }

    public LabourCement(String arg0) {
        super(arg0);
        // TODO Auto-generated constructor stub
    }

    public LabourCement(ThreadGroup arg0, Runnable arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
    }

    public LabourCement(ThreadGroup arg0, String arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
    }

    public LabourCement(Runnable arg0, String arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
    }

    public LabourCement(ThreadGroup arg0, Runnable arg1, String arg2) {
        super(arg0, arg1, arg2);
        // TODO Auto-generated constructor stub
    }

    public LabourCement(ThreadGroup arg0, Runnable arg1, String arg2, long arg3) {
        super(arg0, arg1, arg2, arg3);
        // TODO Auto-generated constructor stub
    }


}



package com.construction.labours;

public class LabourPolishMarbel extends Thread {

    public LabourPolishMarbel() {
        // TODO Auto-generated constructor stub
    }

    public LabourPolishMarbel(Runnable arg0) {
        super(arg0);
        // TODO Auto-generated constructor stub
    }

    public LabourPolishMarbel(String arg0) {
        super(arg0);
        // TODO Auto-generated constructor stub
    }

    public LabourPolishMarbel(ThreadGroup arg0, Runnable arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
    }

    public LabourPolishMarbel(ThreadGroup arg0, String arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
    }

    public LabourPolishMarbel(Runnable arg0, String arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
    }

    public LabourPolishMarbel(ThreadGroup arg0, Runnable arg1, String arg2) {
        super(arg0, arg1, arg2);
        // TODO Auto-generated constructor stub
    }

    public LabourPolishMarbel(ThreadGroup arg0, Runnable arg1, String arg2, long arg3) {
        super(arg0, arg1, arg2, arg3);
        // TODO Auto-generated constructor stub
    }

}




package com.construction.labours;

public class LabourPainting extends Thread {

    public LabourPainting() {
        // TODO Auto-generated constructor stub
    }

    public LabourPainting(Runnable arg0) {
        super(arg0);
        // TODO Auto-generated constructor stub
    }

    public LabourPainting(String arg0) {
        super(arg0);
        // TODO Auto-generated constructor stub
    }

    public LabourPainting(ThreadGroup arg0, Runnable arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
    }

    public LabourPainting(ThreadGroup arg0, String arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
    }

    public LabourPainting(Runnable arg0, String arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
    }

    public LabourPainting(ThreadGroup arg0, Runnable arg1, String arg2) {
        super(arg0, arg1, arg2);
        // TODO Auto-generated constructor stub
    }

    public LabourPainting(ThreadGroup arg0, Runnable arg1, String arg2, long arg3) {
        super(arg0, arg1, arg2, arg3);
        // TODO Auto-generated constructor stub
    }

}

答案 3 :(得分:0)

解决方案:删除调用对象t1

t1.notify()更改为notify()