Java多線程——sleep(),wait(),notify(),notifyAll(),join()

Thread.sleep 與 object.wait()區別

共同點:
1. 兩個方法都會導致線程阻塞
不同點:
1. sleep在阻塞的時候,如果擁有鎖,線程不會釋放鎖;而wait會釋放鎖
3. wait必須在同步代碼塊內使用;sleep則不必

notify(),notifyAll()

共同點:
1. 喚醒wait線程
不同點:
1. notify只喚醒一個wait線程
2. notifyAll喚醒所有wait線程

public class WaitUse {
    public static void main(String[] args) {
        new Thread(new Thread1()).start();
        try {
            Thread.sleep(100);
        } catch (Exception e) {
            e.printStackTrace();
        }
        new Thread(new Thread2()).start();
    }

    private static class Thread1 implements Runnable{
        @Override
        public void run(){
            synchronized (WaitUse.class) {
                System.out.println("enter thread1...");
                System.out.println("thread1 is waiting...");
                try {
                    //調用wait()方法,線程會放棄對象鎖(WaitUse.class)
                    WaitUse.class.wait();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println("thread1 is going on ....");
                System.out.println("thread1 is over!!!");
            }
        }
    }

    private static class Thread2 implements Runnable{
        @Override
        public void run(){
            synchronized (WaitUse.class) {
                System.out.println("enter thread2....");
                System.out.println("thread2 is waiting....");
                System.out.println("notify()");
                //對此對象調用notify()方法後,對應調用該對象wait()方法的線程就會進入等待獲取鎖的狀態(這裏是Thread1)
                //需要注意的是,如果有多個線程調用了wait方法,那notify()只會喚醒其中的一個線程。要想喚醒所有線程,需要調用notifyAll()
                WaitUse.class.notify();
                //==================
                //區別
                //如果我們把代碼:WaitUse.class.notify();給註釋掉,即WaitUse.class調用了wait()方法,但是沒有調用notify()
                //方法,則線程永遠處於掛起狀態。
                try {
                    //sleep()方法導致了程序暫停執行指定的時間,讓出cpu該其他線程,當指定的時間到了又會自動恢復運行狀態。
                    //在調用sleep()方法的過程中,線程不會釋放對象鎖。
                    //Thread.sleep(5000);//方式一:不會釋放鎖,所以只有Thread2 sleep 結束,然後執行完synchronized塊,
                    // Thread1才能獲取到鎖,不然都會一直處於阻塞狀態


                    WaitUse.class.wait();//方式二:會釋放鎖
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println("thread2 is going on....");
                System.out.println("thread2 is over!!!");
            }
        }
    }
}

join()

源碼:

public final void join() throws InterruptedException {
        join(0);
    }
public final synchronized void join(long millis)
    throws InterruptedException {//獲取對象鎖,也就是this
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {//如果子線程已經啓動,並且還沒有運行結束,則調用wait方法,使得當前線程進入等待狀態(會釋放對象鎖this)
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

例子:

public class JoinUse extends Thread {
    public static int a = 0;

    public void run() {
        for (int k = 0; k < 5; k++) {
            a = a + 1;
        }
    }

    public static void main(String[] args) throws Exception {
        Thread t = new JoinUse();
        t.start();
        t.join(); //使得當前線程進入等待狀態,這裏是主線程。知道子線程執行完畢,主線程纔會結束等待
        System.out.println(a);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章