一道面試題 設計4個執行緒,其中兩個每次對j增加1,另外兩個對j每次減少1。迴圈100次。
阿新 • • 發佈:2019-02-12
題目
設計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