【Java多線程編程核心技術】第一章(多線程技能suspend,resume,yield)

1.8 暫停線程

     在多線程中,suspend是暫停線程,resume是恢復線程的執行.

 1.8.1suspend方法和resume方法的使用

public class MyThread extends Thread {
    private long i = 0L;
    public long getI() {
        return i;
    }
    public void setI(long i) {
        this.i = i;
    }
    @Override
    public void run() {
        while(true) {
            i++;
        }
    }
    public static void main(String[] args) {
        try {
            MyThread thread = new MyThread();
            thread.start();
            Thread.sleep(5000);
            // A段
            thread.suspend();
            System.out.println("A= " + System.currentTimeMillis()+" i=" + thread.getI());
            Thread.sleep(5000);
            System.out.println("A= " + System.currentTimeMillis()+" i=" + thread.getI());
            // B段
            thread.resume();
            Thread.sleep(5000);
            // C段
            thread.suspend();
            System.out.println("B= " + System.currentTimeMillis()+" i=" + thread.getI());
            Thread.sleep(5000);
            System.out.println("B= " + System.currentTimeMillis()+" i=" + thread.getI());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

1.8.2 suspend與resume方法的缺點-獨佔

   在使用suspend與resume方法時,如果使用不當,極易造成公共的同步對象的獨佔,使得其它線程無法訪問公共同步對象

public class SynchronizeObj {
    synchronized public void printString() {
        System.out.println("begin");
        if(Thread.currentThread().getName().equals("a")) {
            System.out.println("a 線程永遠suspend..");
            Thread.currentThread().suspend();
        }
        System.out.println("end");
    }

    public static void main(String[] args) {
        try {
            final SynchronizeObj obj = new SynchronizeObj();
            Thread thread1 = new Thread(()->obj.printString());
            thread1.setName("a");
            thread1.start();
            Thread.sleep(500);

            Thread thread2 = new Thread(()->{
                System.out.println("thread2 啓動了, 但是進入不了printString,只打印一個begin");
                System.out.println("因爲printString方法被a線程鎖定並且永遠suspend暫停了");
                obj.printString();
            });
            thread2.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

還有另外一種獨佔鎖的情況也要格外注意,稍有不慎,就會掉進坑裏

public class MyThread extends Thread {
    private long i = 0L;
    public long getI() {
        return i;
    }
    public void setI(long i) {
        this.i = i;
    }
    @Override
    public void run() {
        while(true) {
            i++;
        }
    }
    public static void main(String[] args) {
        try {
            MyThread thread = new MyThread();
            thread.start();
            Thread.sleep(500);
            thread.suspend();
            System.out.println("main end");// 打印,但程序一直阻塞中
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

將run方法的代碼修改如下:

    @Override
    public void run() {
        while(true) {
              i++;
              System.out.println(i);
        }
    }

再次運行發現,i被打印,但是不再打印main end,原因是當程序運行到println方法內部停止時,同步鎖未被釋放.源碼如下

   /**
     * Prints a long and then terminate the line.  This method behaves as
     * though it invokes <code>{@link #print(long)}</code> and then
     * <code>{@link #println()}</code>.
     *
     * @param x  a The <code>long</code> to be printed.
     */
    public void println(long x) {
        synchronized (this) {
            print(x);
            newLine();
        }
    }

1.8.3 suspend與resume方法的缺點-不同步

   在使用suspend與resume方法也容易出現因爲線程的暫停而導致數據不同步的情況. 

public class NoSameValue {

    private String username = "1";
    private String password = "11";

    public void setValue(String u, String p) {
        this.username = u;
        if (Thread.currentThread().getName().equals("a")) {
            System.out.println("stop thread A");
            Thread.currentThread().suspend();
        }
        this.password = p;
    }

    public void printUsernameAndPassword() {
        System.out.println(username + ":" + password);
    }

    public static void main(String[] args) {
        try {
            final NoSameValue obj = new NoSameValue();
            Thread thread1 = new Thread(() -> obj.setValue("a", "aa"));
            thread1.setName("a");
            thread1.start();
            Thread.sleep(500);
            new Thread(()->obj.printUsernameAndPassword()).start();// a:11
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

1.9 yield方法

yield方法的作用是放棄當前的cpu資源,將它讓給其它的任務去佔用cpu執行時間,但放棄的時間不確定,有可能剛剛放棄,馬上又獲得cpu時間片

public class YieldThread extends Thread{
    @Override
    public void run() {
        long beginTime = System.currentTimeMillis();
        int count = 0;
        for(int i=0; i<50000000; i++) {
//            Thread.yield();// 將cpu讓給其它資源導致速度變慢
            count = count + (i+1);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("total time is " +(endTime - beginTime)+ " millisecond");// 21/ yield 17223
    }
    public static void main(String[] args) {
        new YieldThread().start();
    }
}

 

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