Thread其他

      在〈Thread其他〉中尚無留言

死結 Deadlock

多個執行緒互等對方的資源, 造成誰也不讓誰的狀況

Starvation 飢餓

synchronized區塊需花費常時間, 而某執行緒頻繁取得此資源, 造成其他執行緒一直block

Livelock

每支程式都很忙碌, 但並不是死結

Exam1-synchronized的用法

不同的人作不同的事,用相同的工具

只有一台車. 有駕駛A及駕駛B分別要去台北及屏東1000次.

如下程式碼, 若沒有synchronized(car),  就會造成如下紅色部份, 駕駛B取車後, 又被駕駛A搶去

駕駛A 取車 : 去台北 : 842
駕駛B 取車 : 駕駛A 取車 : 去台北 : 843
駕駛A 取車 : 去台北 : 844
去屏東 : 493

package threadtest2;
public class ThreadTest2 {
    public static void main(String[] args) {
        Car car=new Car();
        new Thread(new Runnable(){
            @Override
            public void run() {
                for (int i=0;i<1000;i++){
                    synchronized(car){
                        car.drive();
                        System.out.printf("去台北 : %d\n", i);
                    }
                }
            }
        },"駕駛A").start();
        new Thread(new Runnable(){
            @Override
            public void run() {
                for (int i=0;i<1000;i++){
                    synchronized(car){
                        car.drive();
                        System.out.printf("去屏東 : %d\n", i);
                    }
                }
            }
        },"駕駛B").start();        
    }
}
class Car{
    public void drive(){
        System.out.printf("%s 取車 : ", Thread.currentThread().getName());
    }
}

Exam2-synchronized

不同的人作相同的事, 用相同的工具

只有一台車. 有駕駛A及駕駛B, 二人共同將貨物運出1000次.

如下程式碼, 若沒有synchronized(car),  就會造成如下紅色部份, 駕駛B取車後, 又被駕駛A搶去. 另一個現在是出車數會重複不正確

駕駛A 取車 : 駕駛B 取車 : 送貨去屏東 : 249
送貨去台北 : 249
駕駛B 取車 : 駕駛A 取車 : 送貨去屏東 : 251
駕駛B 取車 : 送貨去台北 : 251
駕駛A 取車 : 送貨去屏東 : 252

請注意, 不同的執行緒執行相同的Runnable時,  Runnable裏的區域變數對每個執行緒都是不一樣的. 也就是說每個執行緒都會copy一份Runnable裏的區域變數, 然後放在自己的stack區. 所以下述的變數 i, 必需宣告為物件變數

package threadtest3;
public class ThreadTest3 {
    public static void main(String[] args) {
        Deliver deliver=new Deliver(new Car());
        Thread t1=new Thread(deliver, "駕駛A");
        t1.start();
        Thread t2=new Thread(deliver, "駕駛B");
        t2.start();        
    }
}
class Deliver implements Runnable{
    Car car;
    int i;
    public Deliver(Car car){
        this.car=car;
    }
    @Override
    public void run() {
        while(true){
            synchronized(car){
                i++;
                if(i<=1000){
                    car.drive();
                    System.out.printf("%s 送出貨物 : %d\n", Thread.currentThread().getName(),i);
                }
                else{
                    break;
                }
            }
        }
    }
}
class Car{
    public void drive(){
        System.out.printf("%s 取車 : ", Thread.currentThread().getName());
    }
}

Exam3-wait作用

不同的人作不同的事, 用相同的工具, 且某種特殊條件才可以作

只有一台車, 有二個駕駛, 單次車次是上台北, 雙次車次是下屏東.

wait() 通常是在某種狀況下, 將擁有此物件的執行緒退出等待, 待另一種狀況發生後, 再notify()通知等待的執行緒進入Runnable階段.

wait(), notify()都是物件變數, 所以要由物件來呼叫

所以wait()一定要在synchronized區塊之中. 這點有點怪怪的, 因為一定要在synchronized之中, 代表執行緒擁有此物件鎖, 然後退出等待, 那鎖呢??  原來wait()時, 執行緒會放棄這把鎖, 所以不會佔著茅坑不拉屎.

package threadtest4;
public class ThreadTest4 {
    public static void main(String[] args) {
        Car car=new Car();
        new Thread(new Runnable(){
            @Override
            public void run() {
                for(int i=0;i<500;i++){
                    car.driveToNorth();
                }
            }
        }, "駕駛A").start();
        new Thread(new Runnable(){
            @Override
            public void run() {
                for(int i=0;i<500;i++){
                    car.driveToSouth();
                }
            }
        }, "駕駛B").start();        
    }
}

class Car{
    int i=1;
    public synchronized void driveToNorth(){
        if(i%2==0){
            try {
                wait();
            } catch (InterruptedException ex) {
            }
        }
        System.out.printf("%s 出車去台北 : %d\n", Thread.currentThread().getName(), i);
        i++;
        notify();
    }
    public synchronized void driveToSouth(){
        if(i%2==1){
            try {
                wait();
            } catch (InterruptedException ex) {
            }
        }
        System.out.printf("%s 出車去屏東 : %d\n", Thread.currentThread().getName(), i);
        i++;
        notify();
    }
}

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *