Java中如何喚醒“指定的“某個線程


 

熟悉線程操作的小朋友應該知道,Java中線程的掛起和喚醒一般用synchronized + wait + notify完成。

比如:

synchronized(o) {

    o.wait(); //wait狀態

}

在其他線程中o.notify(),就可以喚醒在o上wait的線程。

可是如果o上有多個線程wait,是沒有辦法喚醒“指定”的某個線程的。

import java.util.concurrent.TimeUnit;

public class TestNotify extends Thread{
    
    public static void main(String[] args) {
        final Object synObj = new Object();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized(synObj) {
                    System.out.println("1.T1獲取synObj的對象監視器,開始執行同步塊");
                    try {
                        TimeUnit.SECONDS.sleep(2);//休息一分鍾,不放棄鎖
                        System.out.println("T1在 wait()時掛起了");
                        synObj.wait();
                        System.out.println("T1被其他線程喚醒后並重新獲得synObj的對象監視器,繼續執行");
                    }catch(InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("T1獲取synObj的對象監視器,結束同步塊");
                }
            };
        });
        t1.start();

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("T2啟動,但是因為有別的線程占用了synObj的對象監視器,則等待別的線程執行synObj.wait來釋放它");
                synchronized(synObj) {
                    try {
                        System.out.println("T2獲取synObj的對象監視器,進入同步塊");
                        synObj.notify();
                        System.out.println("T2執行synObj.notify()");
                        TimeUnit.SECONDS.sleep(2);
                        System.out.println("T2結束同步塊,釋放synObj的對象監視器");
                    }catch(InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
        });
        t2.start();
        
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("T3啟動,但是因為有別的線程占用了synObj的對象監視器,則等待別的線程執行synObj.wait來釋放它");
                synchronized(synObj) {
                    try {
                        System.out.println("T3獲取synObj的對象監視器,進入同步塊");
                        synObj.notify();
                        System.out.println("T3執行synObj.notify()");
                        TimeUnit.SECONDS.sleep(2);
                        System.out.println("T3結束同步塊,釋放synObj的對象監視器");
                    }catch(InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
        });
        t3.start();
    }
}

 

(2)使用Lock + Condition 實現喚醒指定的部分線程

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test {
    public static Lock lock = new ReentrantLock();
    public static int count = 0;
    
    public static Condition conditionA = lock.newCondition();
    public static Condition conditionB = lock.newCondition();
    
    public static void main(String[] args) {
        Thread t1 = new Thread() {
            @Override
            public void run() {
                lock.lock();
                if (count < 5) {
                    System.out.println("線程1未達到業務要求,暫停中,等待線程2處理到達到要求后喚醒");
                    try {
                        conditionA.await();// 暫停線程並釋放鎖
                        System.out.println("conditionA被喚醒");
                        conditionB.await();
                        System.out.println("conditionB被喚醒");
                        System.out.println("我是線程1后面的代碼");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                lock.unlock();
            }
        };
        
        Thread t2 = new Thread() {
            @Override
            public void run() {
                lock.lock();
                while (count < 10) {
                    count++;
                    System.out.println("線程2業務處理中: " + count);
                    try {
                        Thread.sleep(1000);
                        if (count == 5) {
                            conditionA.signal();
                            System.out.println("喚醒線程1");
                            lock.unlock();// 調用signal()方法后,線程2並不會釋放鎖,需要手動釋放線程2才會執行
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                try {
                    lock.lock();// 不加這個會報java.lang.IllegalMonitorStateException
                    System.out.println("等待3秒后conditionB會被喚醒");
                    Thread.sleep(3000);
                    conditionB.signal();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                lock.unlock();// 這里釋放鎖,線程2執行完,線程1才會執行
            }
        };
        
        t1.start();
        t2.start();
    }
}

console輸出:

 

 (3) 使用Java6引入的LockSupport這個類。

import java.util.concurrent.locks.LockSupport;

public class TestLockSupport {

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            System.out.println("start");
            LockSupport.park(); //一直wait
            System.out.println("continue");
        });
        
        t.start();
        Thread.sleep(2000);
        LockSupport.unpark(t); //指定t線程解除wait態
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM