notify和wait

題目:啓動三個線程,使他們有序的交替的打印0-100java

最開始我想到的是bash

import java.util.concurrent.atomic.AtomicInteger;

public class ThreadTest3 implements Runnable {

    private static final AtomicInteger atomicInteger = new AtomicInteger(0);
    private int i = 0;

    public static void main(String[] args) {
        ThreadTest3 t = new ThreadTest3();
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        t1.setName("t1");
        t2.setName("t2");
        t3.setName("t3");
        t1.start();
        t2.start();
        t3.start();
    }


    @Override
    public void run() {
        while (true){
            if(atomicInteger.get() <100){
                System.out.println(Thread.currentThread().getName() + "_" + atomicInteger.getAndIncrement());
            }else {
                    break;
                }
        }
    }
}
複製代碼

結果出來的是ide

t1_0
t1_2
t1_3
t1_4
t1_5
t2_1
t2_7
t1_6
t1_9
t1_10
t1_11
t1_12
t1_13
t1_14
t1_15
t1_16
t1_17
t1_18
t2_8
......
複製代碼

一看就是既沒有交替有沒有有序ui

交替的話,須要一個線程執行完成以後,放棄cpu的資源,想到的就是wait方法,執行wait以前須要執行notify把其餘的線程先喚醒this

因而就有了第二個版本atom

public class ThreadTest7 extends Thread {

    private Object lock;
    private static int i;

    public ThreadTest7(Object lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (this) {
                notify();
                if (i < 100) {
                    System.out.println(Thread.currentThread().getName() + "_" + i);
                    i++;
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else {
                    break;
                }
            }

        }
    }

    public static void main(String[] args) {
        Object lock = new Object();
        Thread t1 = new ThreadTest7(lock);
        Thread t2 = new ThreadTest7(lock);
        Thread t3 = new ThreadTest7(lock);
        t1.setName("t1");
        t2.setName("t2");
        t3.setName("t3");
        t1.start();
        t2.start();
        t3.start();
    }
}

複製代碼

輸出結果爲:交替是交替了,可是沒有打完spa

t1_0
t2_1
t3_2
沒有而後了
複製代碼

查了網上的資料,線程

public class ThreadTest4 implements Runnable{

    int i = 1;

    public static void main(String[] args) {
        ThreadTest4 t = new ThreadTest4();
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);

        t1.setName("線程1");
        t2.setName("線程2");

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

    public void run() {
        while (true) {
            synchronized (this) {
                // 先喚醒另一個線程
                notify();
                if (i <= 100) {
                    System.out.println(this.getClass().getName() + "_" +  this.hashCode());
                    System.out.println(Thread.currentThread().getName() + ":"+ i);
                    i++;
                    try {
                        // 打印完以後,釋放資源,等待下次被喚醒
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else {
                    break;
                }
            }
        }
    }

}
複製代碼

結果果真能夠交替有序的把數字打印出來了。code

Runnable和Thread建立線程的區別
Runnable r = new Runnable();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1和t2會共享到r中的屬性,好比上例中的i,以及this也是同一個Runnable t.資源

notify、notifyAll 和 wait

這三個方法都是Object的方法,

方法 註釋
notify Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of them is chosen to be awakened
notifyAll Wakes up all threads that are waiting on this object's monitor. A thread waits on an object's monitor by calling one of the {@code wait} methods.
wait Causes the current thread to wait until another thread invokes the {@link java.lang.Object#notify()} method or the{@link java.lang.Object#notifyAll()} method for this object.

notify和notifyAll起做用的前提是,他們須要獲取同一個object實例的monitor(synchronized的實現原理,synchronized修飾的代碼塊編譯完了以後,實際上是monitorenter和monitorexit兩個指令包的,要否則沒法喚醒其餘的線程,就像個人ThreadTest7。

因此這三個方法必須放在同步代碼塊中,當線程執行wait()時,會把當前的鎖釋放,而後讓出CPU,進入等待狀態。

按照上面的概念,因此若是要使用Thread不用Runnable的話,可使用下面的方式

public class ThreadTest6 extends Thread {

    private static Object lock = new Object();

    private static int i;


    @Override
    public void run() {
        while (true) {

            synchronized (lock) {
                lock.notify();
                if (i < 100) {
                    System.out.println(Thread.currentThread().getName() + "_" + i);
                    i++;
                }
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }
    }

    public static void main(String[] args) {
        Thread t1 = new ThreadTest6();
        Thread t2 = new ThreadTest6();
        Thread t3 = new ThreadTest6();
        t1.setName("t1");
        t2.setName("t2");
        t3.setName("t3");
        t1.start();
        t2.start();
        t3.start();
    }
}

複製代碼
相關文章
相關標籤/搜索