1. 程式人生 > >一道面試題 設計4個執行緒,其中兩個每次對j增加1,另外兩個對j每次減少1。迴圈100次。

一道面試題 設計4個執行緒,其中兩個每次對j增加1,另外兩個對j每次減少1。迴圈100次。

題目

設計4個執行緒,其中兩個執行緒每次對j增加1,另外兩個執行緒對j每次減少1。迴圈100次。寫出程式。

解法1

書上的答案是用內部類實現的,網上的答案基本都是照抄書上的。感覺不是很優雅,想自己實現以下。

package a;

public class Test {

    private int j;

    public static void main(String[] args) {
        Test t = new Test();
        for(int i =0;i<2;i++) {
            Thread t1 = new
Inc(t); t1.start(); Thread t2 = new Dec(t); t2.start(); } } public synchronized void inc() { j++; System.out.println(Thread.currentThread().getName() + ":inc" + j); } public synchronized void dec() { j--; System.out.println(Thread.currentThread().getName() + ":dec"
+ j); } } class Inc extends Thread { private Test a; Inc(Test a) { this.a = a; } @Override public void run() { for (int i = 0; i < 100; i++) { a.inc(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } class
Dec extends Thread {
private Test a; Dec(Test a) { this.a = a; } @Override public void run() { for (int i = 0; i < 100; i++) { a.dec(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }

注意,如果同步實現正確的話,最後的輸出是0。如果同步不正確,可能出現 j++的中途步驟 temp = j+1;又進行了 j-1 ,那麼最後的結果就不是0了。

這兒 synchronized 關鍵詞載入方法前面,所以是針對某個類的例項加鎖的,也就是說我們只有一個Test例項,把該例項作為建構函式的引數傳遞給 Thread 類。然後一個執行緒對該例項的 j 變數操作的適合會加鎖,其他執行緒對 j 操作需要等待鎖的釋放。這樣就實現了同步。

本程式碼的輸出都是0.

Thread-1:dec0
Thread-2:inc1
Thread-3:dec0
Thread-0:inc1
Thread-1:dec0
Thread-2:inc1
Thread-3:dec0
Thread-0:inc1
Thread-1:dec0

非同步

把 synchronized 關鍵詞去掉,加上 sleep(100) 可以增大執行緒衝突的可能性。

public   void inc() {
    j++;
    System.out.println(Thread.currentThread().getName() + ":inc" + j);
}

public   void dec() {
    j--;
    System.out.println(Thread.currentThread().getName() + ":dec" + j);
}

結果1

Thread-3:dec-8
Thread-2:inc-8
Thread-1:dec-8
Thread-2:inc-7
Thread-0:inc-6
Thread-3:dec-7
Thread-1:dec-7

結果2

Thread-1:dec11
Thread-2:inc12
Thread-3:dec11
Thread-0:inc11
Thread-1:dec10
Thread-2:inc11
Thread-3:dec11
Thread-0:inc11
Thread-1:dec12
Thread-2:inc12

可以看出因為沒加同步,最後的結果無法預知。

內部類方法

參考網上的文章,這兒的註釋很詳細

package a;

public class ManyThread {
    // 採用 Runnable 介面方式建立的多條執行緒可以共享例項屬性

    private int i;
    // 同步增加方法

    private synchronized void inc() {
        i++;
        System.out.println(Thread.currentThread().getName() + "--inc--" + i);
    }

    // 同步減算方法

    private synchronized void dec() {
        i--;
        System.out.println(Thread.currentThread().getName() + "--dec--" + i);
    }

    // 增加執行緒 注意是內部類,且是非靜態的
    class Inc implements Runnable {
        public void run() {
            int i = 0;
            while (i++ < 100) {
                inc();
            }
        }
    }

    // 減算執行緒 注意是內部類,且是非靜態的
    class Dec extends Thread {
        public void run() {
            int i = 0;
            while (i++ < 100) {
                dec();
            }
        }
    }

    public static void main(String[] args) {

        // 由於內部類是非靜態的,所以這樣需要Test的例項化才能呼叫生成內部類例項
        ManyThread t = new ManyThread();

        // 內部類的例項化
        Inc inc = t.new Inc(); //
        // Dec dec = t. new Dec();

        Thread thread = null;
        // 建立 2 個增加執行緒
        for (int i = 0; i < 2; i++) {
            thread = new Thread(inc); // 實現Runnable的類的例項化,使用帶引數的Thread構造方法.
            thread.start();
        }

        // 建立 2 個減少執行緒
        for (int i = 0; i < 2; i++) {
            thread = t.new Dec(); // 繼承Thread的類可以直接例項化.
            thread.start();
        }

    }

}

輸出結果最後也是0,執行緒執行的順序不固定,但最後結果都是0.

Thread-3--dec--7
Thread-3--dec--6
Thread-3--dec--5
Thread-3--dec--4
Thread-3--dec--3
Thread-3--dec--2
Thread-3--dec--1
Thread-3--dec--0

參考文章