【Java】【基礎篇】day12:線程安全與同步機制

前言

本期任務:畢向東老師Java視頻教程學習筆記(共計25天)


代碼

/*
需求:輸入方保存一個人,輸出方打印一個人,交替執行

線程間通訊:
其實就是多個線程在操作同一個資源,
但是操作的動作不同。

*/

//notifyAll();

/*
wait:
notify();
notifyAll();

都使用在同步中,因爲要對持有監視器(鎖)的線程操作。
所以要使用在同步中,因爲只有同步才具有鎖。

爲什麼這些操作線程的方法要定義Object類中呢?
因爲這些方法在操作同步中線程時,都必須要標識它們所操作線程只有的鎖,
只有同一個鎖上的被等待線程,可以被同一個鎖上notify喚醒。
不可以對不同鎖中的線程進行喚醒。

也就是說,等待和喚醒必須是同一個鎖。

而鎖可以是任意對象,所以可以被任意對象調用的方法定義Object類中。


*/

package day12;

class Resourse1 {
    String name;
    String sex;
    boolean flag = false; // 默認當前無資源
}


class Input implements Runnable {
    private Resourse1 r;

    Input(Resourse1 r) {
        this.r = r;
    }

    public void run() {
        int x = 0;
        while (true) {
            synchronized (r) {
                if (r.flag)
                    try {
                        r.wait(); //爲保證交替進行,生成一個新對象之後,下一次則進入等待狀態
                    } catch (Exception e) {

                    }
                if (x == 0) {
                    r.name = "mike";
                    r.sex = "man";
                } else {
                    r.name = "麗麗";
                    r.sex = "女";
                }
                r.flag = true;
                r.notify(); // 喚醒處於等待的一個線程,若有多個,則隨機喚醒
                x = (x + 1) % 2;
            }


        }
    }

}


class Output implements Runnable {
    private Resourse1 r;

    Output(Resourse1 r) {
        this.r = r;
    }

    public void run() {
        while (true) {
            synchronized (r) {
                if (!r.flag)
                    try {
                        r.wait();
                    } catch (Exception e) {

                    }
                r.flag = false;

                r.notify();

                if ((r.name == "mike" && r.sex == "女") || (r.name == "麗麗" && r.sex == "man")) // 判斷是否出現線程不安全現象:人妖
                System.out.println(r.name + "......" + r.sex);
            }

        }

    }
}


public class InputOutputDemo {
    public static void main(String[] args) {
        Resourse1 r = new Resourse1();
        new Thread(new Input(r)).start();
        new Thread(new Output(r)).start();
    }
}

/*
優化InputOutputDemo
*/
package day12;

class Resourse2 {
    String name;
    String sex;
    private int x;
    boolean flag = false; // 默認當前無資源

    public synchronized void set() {
        if (flag)
            try {
                wait(); //爲保證交替進行,生成一個新對象之後,下一次則進入等待狀態
            } catch (Exception e) {

            }
        if (x == 0) {
            name = "mike";
            sex = "man";
        } else {
            name = "麗麗";
            sex = "女";
        }

        flag = true;
        x = (x + 1) % 2;

        this.notify(); // 喚醒處於等待的一個線程,若有多個,則隨機喚醒
    }

    public synchronized void out() {
        if (!flag)
            try {
                wait();
            } catch (Exception e) {

            }
        flag = false;

        this.notify();

        if ((name == "mike" && sex == "女") || (name == "麗麗" && sex == "man")) // 判斷是否出現線程不安全現象:人妖
            System.out.println(name + "......" + sex);
    }
}


class Input2 implements Runnable {
    private Resourse2 r;

    Input2(Resourse2 r) {
        this.r = r;
    }

    public void run() {
        while (true) {
            {
                r.set();
            }
        }

    }
}

class Output2 implements Runnable {
    private Resourse2 r;

    Output2(Resourse2 r) {
        this.r = r;
    }

    public void run() {
        while (true) {
            r.out();
        }

    }
}

public class InputOutputOptimize {
    public static void main(String[] args) {
        Resourse2 r = new Resourse2();
        new Thread(new Input2(r)).start();
        new Thread(new Output2(r)).start();
    }
}
/*
需求:生產者生產一個商品,消費者消費一個商品,交替進行

JDK1.5 中提供了多線程升級解決方案。
將同步Synchronized替換成現實Lock操作。
將Object中的wait,notify notifyAll,替換了Condition對象。
該對象可以Lock鎖 進行獲取。
該示例中,實現了本方只喚醒對方操作。

Lock:替代了Synchronized
	lock
	unlock
	newCondition()

Condition:替代了Object wait notify notifyAll
	await();
	signal();
	signalAll();


*/

package day12;

import java.util.concurrent.locks.*;

class Resourse {

    private String name;
    private int count = 1;
    private boolean flag = false; // 保證生產者和消費者有且僅有一方在操作

    private Lock lock = new ReentrantLock();

    private Condition condition_pro = lock.newCondition();
    private Condition condition_con = lock.newCondition();

    public void set(String name) throws InterruptedException {
        lock.lock();
        try {
            while (flag)
                condition_pro.await(); //喚醒消費者
            this.name = name + "......" + count++;
            System.out.println(Thread.currentThread().getName() + "生產者" + this.name);
            flag = true; //生產完畢,生產者應該等待
            condition_con.signal(); // 給消費者發送信號,通知其進行消費
        } finally {
            lock.unlock(); //釋放鎖的動作一定要執行
        }
    }

    public void out() throws InterruptedException {
        lock.lock();
        try {
            while (!flag)
                condition_con.await();
            System.out.println(Thread.currentThread().getName() + "消費者............" + this.name);
            flag = false;
            condition_pro.signal();
        } finally {
            lock.unlock();//釋放鎖的動作一定要執行
        }


    }


}


class Producer implements Runnable {

    private Resourse res;

    Producer(Resourse res) {
        this.res = res;
    }

    public void run() {
        while (true) {
            try {
                res.set("商品");
            } catch (InterruptedException e) {

            }

        }
    }
}

class Consumer implements Runnable {

    private Resourse res;

    Consumer(Resourse res) {
        this.res = res;
    }

    public void run() {
        while (true) {
            try {
                res.out();
            } catch (InterruptedException e) {

            }

        }
    }
}


public class ProducerConsumerDemo {
    public static void main(String[] args) {

        Resourse res = new Resourse();

        Producer p1 = new Producer(res);
        Producer p2 = new Producer(res);
        Consumer c1 = new Consumer(res);
        Consumer c2 = new Consumer(res);

        new Thread(p1).start();
        new Thread(p2).start();
        new Thread(c1).start();
        new Thread(c2).start();


    }
}

/*
join:
當A線程執行到了B線程的.join()方法時,A就會等待。等B線程都執行完,A纔會執行。

join可以用來臨時加入線程執行。


*/

package day12;


class Demo implements Runnable {
    private int size = 1000;

    Demo(int size) {
        this.size = size;
    }

    Demo() {
    }

    public void run() {
        for (int x = 0; x < size; x++) {
            System.out.println(Thread.currentThread().getName() + "......" + x);
//            System.out.println(Thread.currentThread().toString() + "......" + x);
            Thread.yield();  // 暫停當前線程,釋放資源,保證多線程能交替運行,不嚴格交替
        }
    }
}


public class JoinDemo {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(new Demo(1000));
        Thread t2 = new Thread(new Demo());
        t1.start();

//        t1.setPriority(Thread.MIN_PRIORITY); //設置最低權限
//        t2.setPriority(Thread.MAX_PRIORITY); // 設置最高權限

//        t1.join(); // 在主線程中搶奪CPU執行權,當前激活狀態的線程只有t1,直到t1全部執行完畢,主線程與t2交替執行

        t2.start();

//        t1.join(); // 在主線程中搶奪CPU執行權,當前激活狀態的線程有t1,t2,直到t1全部執行完畢,主線程與t2交替執行

//        for (int x = 0; x < 1000; x++) {
//            System.out.println(Thread.currentThread().getName() + "......" + x);
////            System.out.println(Thread.currentThread().toString() + "......" + x);
//        }

//        t1.join();// 在主線程中搶奪CPU執行權,當前激活狀態的線程有t1,t2,main,三者交替執行

        System.out.println("over");


    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章