線程(5)--關於同步、死鎖

一.關於同步

1.什麼情況下需要同步

  • 當多線程併發, 有多段代碼同時執行時, 我們希望某一段代碼執行的過程中CPU不要切換到其他線程工作. 這時就需要同步.

  • 如果兩段代碼是同步的, 那麼同一時間只能執行一段, 在一段代碼沒執行結束之前, 不會執行另外一段代碼.
    2.同步代碼塊

  • 使用synchronized關鍵字加上一個鎖對象來定義一段代碼, 這就叫同步代碼塊

  • 多個同步代碼塊如果使用相同的鎖對象, 那麼他們就是同步的
    3.非靜態方法的鎖對象是: this
    4.靜態方法的鎖對象是:字節碼對象,也就是這個方法對應所在的那個類的.class對象,

package com.fenqing.duoxiancheng;

public class d11_Synchronized {

    public static void main(String[] args) {
        final Printer p=new Printer();
        new Thread(){
            public void run(){
                while(true){
                    p.print1();
                }
            }
        }.start();
        new Thread(){
            public void run(){
                while(true){
                    p.print2();
                }
            }
        }.start();
    }

}
class Printer {
    static demo d = new demo();
    public static void print1() {       //方法是static,所以鎖對象也要用static修飾
        //synchronized(new demo()){     //不能用匿名對象,因爲匿名對象不是同一個對象,也就是說不是同一把鎖
        synchronized(d){                //鎖對象可以是任意對象,但是被鎖的代碼需要保證是同一把鎖,
            System.out.print("計");      
            System.out.print("算");
            System.out.print("機");
            System.out.print("\r\n");
        }
    }

    public static void print2() {   
        synchronized(d){    
            System.out.print("軟");
            System.out.print("件");
            System.out.print("工");
            System.out.print("程");
            System.out.print("\r\n");
        }
    }

    public synchronized void print3(){  //定義同步方法
        System.out.print("專");
        System.out.print("業");
        System.out.print("\r\n");
    }
}

class demo{

}

線程安全性

  • 多線程併發操作同一數據時, 就有可能出現線程安全問題
  • 使用同步技術可以解決這種問題, 把操作數據的代碼進行同步, 不要多個線程一起操作

關於同步的練習

四個窗口出售100張票的問題。

1,用Thread()的構造實現

package com.fenqing.duoxiancheng;

public class d12_sell {

    public static void main(String[] args) {
        TicketsSeller t1 = new TicketsSeller();
        TicketsSeller t2 = new TicketsSeller();
        TicketsSeller t3 = new TicketsSeller();
        TicketsSeller t4 = new TicketsSeller();

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        t4.setName("窗口4");

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

}
class TicketsSeller extends Thread {
    private static int tickets = 100;
    static Object obj = new Object();
    public TicketsSeller() {
        super();

    }
    public TicketsSeller(String name) {
        super(name);
    }
    public void run() {
        while(true) {
            synchronized(obj) {
                if(tickets <= 0) 
                    break;
                try {
                    Thread.sleep(10);//線程1睡,線程2睡,線程3睡,線程4睡
                } catch (InterruptedException e) {

                    e.printStackTrace();
                }
                System.out.println(getName() + "...這是第" + tickets-- + "號票");
            }
        }
    }
}

2.用Runnable實現

package com.fenqing.duoxiancheng;

public class d13_sell {

    public static void main(String[] args) {
        Ticket t=new Ticket();
        new Thread(t).start();
        new Thread(t).start();
        new Thread(t).start();
        new Thread(t).start();
    }

}
class Ticket implements Runnable {
    private  int tickets = 100;
    public void run() {
        while(true) {
            synchronized(Ticket.class) {
                if(tickets <= 0) 
                    break;
                try {
                    Thread.sleep(10);//線程1睡,線程2睡,線程3睡,線程4睡
                } catch (InterruptedException e) {

                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"...這是第" + tickets-- + "號票");
            }
        }
    }
}

死鎖——哲學家進餐的問題

  • 多線程同步的時候, 如果同步代碼嵌套, 使用相同鎖, 就有可能出現死鎖。

不清楚這個問題的可以看看哲學家就餐問題簡介

package com.fenqing.duoxiancheng;

public class d14_deathLock {

    private static String s1 = "筷子左";       //定義兩個變量
    private static String s2 = "筷子右";

    public static void main(String[] args) {
        new Thread() {
            public void run() {
                while(true) {
                    synchronized(s1) {
                        System.out.println(getName() + "...拿到" + s1 + "等待" + s2);
                        synchronized(s2) {
                            System.out.println(getName() + "...拿到" + s2 + "開喫");
                        }
                    }
                }
            }
        }.start();

        new Thread() {
            public void run() {
                while(true) {
                    synchronized(s2) {
                        System.out.println(getName() + "...拿到" + s2 + "等待" + s1);
                        synchronized(s1) {
                            System.out.println(getName() + "...拿到" + s1 + "開喫");
                        }
                    }
                }
            }
        }.start();
    }

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