Java — Thread Signaling

原文:http://tutorials.jenkov.com/java-concurrency/thread-signaling.html

线程信号的目的是为了线程间能够相互发送信号,并且也能使线程去等待其他线程的信号。例如一个线程B可能等待一个来至于线程A的信号,用来表明数据已经处理好了。

Signaling via Shared Objects

一种简单的线程通信(线程间进行信号的发送)是使用共享相同的对象变量。

    public class MySignal {
        protected boolean hasDataToProcess = false;
        public synchronized boolean hasDataToProcess() {
            return this.hasDataToProcess;
        }
        public synchronized void setHasDataToProcess(boolean hasData) {
            this.hasDataToProcess = hasData;
        }
    }

多个线程必须共享同一个变量。

Busy Wait

一个线程一直在等待另外一个线程改变共享变量的为其期望值,称为 Busy Wait。

protected MySignal sharedSignal = ...
...
while(!sharedSignal.hasDataToProcess()){
  //do nothing... busy waiting
}

wait(),notify() and notifyAll()

Busy waiting 不是一种非常有效地利用CPU来运行等待线程,即容易造成CPU的浪费,除非等待线程所耗费的时间非常短。更好的方式waiting thread 能够sleep或者inactive当接受到等待信号时。
Java中使用wait(),notify(),notifyAll()来完成这些工作。

A thread that calls wait() on any object becomes inactive until another thread calls notify() on that object. In order to call either wait() or notify the calling thread must first obtain the lock on that object. In other words, the calling thread must call wait() or notify() from inside a synchronized block. Here is a modified version of MySignal called MyWaitNotify that uses wait() and notify().

也就是说,wait、notify、notifyAll必须加上synchronized关键字,且所对象必须是用一个对象。

    public class MyWaitNotify {
        MonitorObject myMonitorObject = new MonitorObject();
        public void doWait() {
            synchronized (myMonitorObject) {
                try {
                    myMonitorObject.wait();
                } catch (InterruptedException e) {...}
            }
        }
        public void doNotify() {
            synchronized (myMonitorObject) {
                myMonitorObject.notify();
            }
        }
    }

Missed Signals

如果一个线程在调用wait时先调用了notify,容易出现信号丢失的情况,直接导致线程waiting forever

    public class MyWaitNotify2 {
        MonitorObject myMonitorObject = new MonitorObject();
        boolean wasSignalled = false;
        public void doWait() {
            synchronized (myMonitorObject) {
                if (!wasSignalled) {
                //  In fact it only calls wait() if no signal was received in between the previous doWait() call and this.
                    try {
                        myMonitorObject.wait();
                    } catch (InterruptedException e) {...}
                }
                //clear signal and continue running.
                wasSignalled = false;
            }
        }
        public void doNotify() {
            synchronized (myMonitorObject) {
                wasSignalled = true;
                myMonitorObject.notify();
            }
        }
    }

Spurious Wakeups

For inexplicable reasons it is possible for threads to wake up even if notify() and notifyAll() has not been called. This is known as spurious wakeups. Wakeups without any reason.

    public class MyWaitNotify3 {
        MonitorObject myMonitorObject = new MonitorObject();
        boolean wasSignalled = false;
        public void doWait() {
            synchronized (myMonitorObject) {
            // 线程可能被一些未知的原因而唤醒,所以必须使用循环
                while (!wasSignalled) {
                    try {
                        myMonitorObject.wait();
                    } catch (InterruptedException e) {...}
                }
                //clear signal and continue running.
                wasSignalled = false;
            }
        }
        public void doNotify() {
            synchronized (myMonitorObject) {
                wasSignalled = true;
                myMonitorObject.notify();
            }
        }
    }

Multiple Threads Waiting for the Same Signals

The while loop is also a nice solution if you have multiple threads waiting, which are all awakened using notifyAll(), but only one of them should be allowed to continue. Only one thread at a time will be able to obtain the lock on the monitor object, meaning only one thread can exit the wait() call and clear the wasSignalled flag. Once this thread then exits the synchronized block in the doWait() method, the other threads can exit the wait() call and check the wasSignalled member variable inside the while loop. However, this flag was cleared by the first thread waking up, so the rest of the awakened threads go back to waiting, until the next signal arrives.

Don’t call wait() on constant String’s or global objects

不要使用String类型去做锁对象,因为在编译期间很多常量String都会直接放入常量池中,被共享。

    public class MyWaitNotify{
        String myMonitorObject = "";
        boolean wasSignalled = false;
        public void doWait(){
            synchronized(myMonitorObject){
                while(!wasSignalled){
                    try{
                        myMonitorObject.wait();
                    } catch(InterruptedException e){...}
                }
                //clear signal and continue running.
                wasSignalled = false;
            }
        }
        public void doNotify(){
            synchronized(myMonitorObject){
                wasSignalled = true;
                myMonitorObject.notify();
            }
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值