多線程2

synchronized使用
同步代碼塊:synchronized放在對象前面,限制一段代碼的執行。鎖可以是任意對象,但多個線程用的必須是同一把鎖。
synchronized(鎖對象){
需要同步的代碼
}
同步方法:synchronized放在方法聲明中,表示整個方法是同步方法。鎖是this
public synchronized void method(){ }
靜態同步方法:synchronized放在靜態方法聲明中,表示整個方法是同步方法。鎖是字節碼文件對象,類名.getclass()。
public static synchronized void method(){ }

同步特點:
好處:同步解決了多線程的安全問題
弊端:當線程很多時,每個線程都會判斷同步上的鎖,很耗費資源,降低程序的執行效率

容器類的線程安全:
可以用synchronized來鎖住這個對象:
synchronized(list){
list.add(…);
}
可以使用java.uitl.Collections的synchronizedXXX()方法來返回一個同步化的容器對象
List list = Collections.synchronizedList(new ArrayList());
這種方式在迭代時仍要用synchronized修飾

List list = Collections.synchronizedList(new ArrayList());   
     ...    
   synchronized(list) {         
         Iterator i = list.iterator();         
         while (i.hasNext()) { 
                   foo(i.next());      
           }   
 }

死鎖
產生原因
有同步嵌套,兩個線程都在等待對方已經鎖定的資源。

public class TestDead {
    public static void main(String[] args) {
        RichMan man = new RichMan();
        man.setName("富翁");
        Kidnapper napper = new Kidnapper();
        napper.setName("綁匪");
        man.start();
        napper.start();
    }
}
class Lock {
    public static Object obj1 = new Object();
    public static Object obj2 = new Object();
}

//描述富翁
class RichMan extends Thread{
    @Override
    public void run() {
        synchronized (Lock.obj1) {
            System.out.println("富翁說:你放了我兒子");
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            synchronized (Lock.obj2) {
                System.out.println("富翁說:我給你1000萬");
            }
        }

    }
}
//描述綁匪
class Kidnapper extends Thread{
    @Override
    public void run() {
        synchronized (Lock.obj2) {
            System.out.println("綁匪說:你給我1000萬");
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            synchronized (Lock.obj1) {
                System.out.println("綁匪說:我放了你兒子");
            }
        }
    }
}

如何避免死鎖:
一個通用的經驗法則是:當幾個線程都要訪問共享資源(鎖)A、B、C時,保證使每個線程都按照同樣的順序去訪問它們,比如都先訪問A,再訪問B和C。
此外,Thread類的suspend()方法也很容易導致死鎖,因此這個方法已經被廢棄了.

線程的等待與喚醒(生產者與消費者問題)
notify(),wait()等是Object中方法,因爲鎖是任意對象,所有這麼方法通過鎖來使用
wait和sleep的區別:
1、sleep任何時候都可以調用,但是wait只能用在同步中。
2、sleep可以在規定時間內醒過來,但是wait需要喚醒,等待的時間是不確定。
3、sleep睡眠中不會交出鎖,但是wait會交出同步鎖。

生產者和消費者模型

package com.qianfeng.producecustomer;
/*
 * 生產者生產6個,消費者6個
 * 包子。
 * 一個生產者,一個消費者。
 * String
 * StringBuffer:同步的。效率不高
 * StringBuilder:不同步的。效率高。很多時候是單線程。
 * 擴展:
 *         線程池的概念。
 *     作業:
 *         1:將生產多個和消費多個,改成集合和數組來實現。
 *     
 */
public class TestProduce2 {
    public static void main(String[] args) {
        MyCustomer customer  = new MyCustomer();
        customer.start();
        MyProduce produce = new MyProduce();
        produce.start();
    }
}
class MyBaozi{
    public static int count = 0;
    public static final Integer SUM = 6;//總數。
}
class MyProduce extends Thread{
    @Override
    public void run() {
        while(true){
            //先判斷。滿了就等待。
            synchronized (MyBaozi.SUM) {
                if(MyBaozi.count>=MyBaozi.SUM){
                    //等待
                    try {
                        MyBaozi.SUM.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                //否則
                MyBaozi.count++;
                try {
                    Thread.sleep((int)(Math.random()*100));
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("生產者生產了一個包子,現有"+MyBaozi.count+"個包子");
                MyBaozi.SUM.notify();

            }

        }
    }
}
class MyCustomer extends Thread{
    @Override
    public void run() {
        while(true){
            synchronized (MyBaozi.SUM) {
                if(MyBaozi.count==0){
                    try {
                        MyBaozi.SUM.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                //消費
                MyBaozi.count--;
                try {
                    Thread.sleep((int)(Math.random()*100));
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("消費者消費了一個包子,現有"+MyBaozi.count+"個包子");
                MyBaozi.SUM.notify();
            }
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章