Java 學習記錄104 — Synchronisation

張小雄
8 min readJan 14, 2022

--

承上篇 103 — Multiple Threads

如果出現 Thread Interference 該怎麼解?

MultipleThreads.java

import thread.ThreadColor;public class MultipleThreads {
public static void main(String[] args) {
Countdown countdown1 = new Countdown();
Countdown countdown2 = new Countdown();
CountdownThread t1 = new CountdownThread(countdown1);
t1.setName("Thread 1");
CountdownThread t2 = new CountdownThread(countdown2);
t2.setName("Thread 2");
t1.start();
t2.start();
}
}
class Countdown {
private int i;
public void doCountdown() {
String color;
switch (Thread.currentThread().getName()) {
case "Thread 1":
color = ThreadColor.ANSI_CYAN;
break;
case "Thread 2":
color = ThreadColor.ANSI_PURPLE;
break;
default:
color = ThreadColor.ANSI_GREEN;
}
for (i = 10; i > 0; i--) {
System.out.println(color + Thread.currentThread().getName() + ": i=" + i);
}
}
}
class CountdownThread extends Thread {
private Countdown threadCountdown;
public CountdownThread(Countdown countdown) {
this.threadCountdown = countdown;
}
@Override
public void run() {
threadCountdown.doCountdown();
}
}

輸出結果:

Thread 2: i=10

Thread 2: i=9

Thread 2: i=8

Thread 2: i=7

Thread 2: i=6

Thread 2: i=5

Thread 2: i=4

Thread 2: i=3

Thread 2: i=2

Thread 1: i=10

Thread 1: i=9

Thread 1: i=8

Thread 1: i=7

Thread 1: i=6

Thread 1: i=5

Thread 1: i=4

Thread 1: i=3

Thread 1: i=2

Thread 1: i=1

Thread 2: i=1

簡單的解法就是,不要使用同一個 countdown 就好,現在拆成兩個,各自使用就不會有問題

但 Tim 也說了,現實中的應用是不太能使用這種解法

例如在銀行、員工系統。就不能有兩個同樣的 object 來做使用

像是銀行櫃台操作了客戶的帳戶,客戶也在網頁上操作帳戶,那兩個 object 的值不一樣時,最後要用哪一個?

會有不同 Thread 對帳戶進行操作,這種情況當然不能使用這種解法

修改 MultipleThreads.java

import thread.ThreadColor;public class MultipleThreads {
public static void main(String[] args) {
Countdown countdown = new Countdown(); CountdownThread t1 = new CountdownThread(countdown);
t1.setName("Thread 1");
CountdownThread t2 = new CountdownThread(countdown);
t2.setName("Thread 2");
t1.start();
t2.start();
}
}
class Countdown {
private int i;
public synchronized void doCountdown() {
String color;
switch (Thread.currentThread().getName()) {
case "Thread 1":
color = ThreadColor.ANSI_CYAN;
break;
case "Thread 2":
color = ThreadColor.ANSI_PURPLE;
break;
default:
color = ThreadColor.ANSI_GREEN;
}
for (i = 10; i > 0; i--) {
System.out.println(color + Thread.currentThread().getName() + ": i=" + i);
}
}
}
class CountdownThread extends Thread {
private Countdown threadCountdown;
public CountdownThread(Countdown countdown) {
this.threadCountdown = countdown;
}
@Override
public void run() {
threadCountdown.doCountdown();
}
}

輸出結果:

Thread 1: i=10

Thread 1: i=9

Thread 1: i=8

Thread 1: i=7

Thread 1: i=6

Thread 1: i=5

Thread 1: i=4

Thread 1: i=3

Thread 1: i=2

Thread 1: i=1

Thread 2: i=10

Thread 2: i=9

Thread 2: i=8

Thread 2: i=7

Thread 2: i=6

Thread 2: i=5

Thread 2: i=4

Thread 2: i=3

Thread 2: i=2

Thread 2: i=1

第二個解法則是使用 synchronized

先把 countdown 還原回去,變回原本的一個

然後在 doCountdown() 前面加上關鍵字 synchronized

這樣能確保只有一個 Thread 能使用該 Method

從輸出結果來看,可以看到一組用完才換下一組 Thread

這樣就不會出現 Thread Interference 的問題

修改 MultipleThreads.java

import thread.ThreadColor;public class MultipleThreads {
public static void main(String[] args) {
Countdown countdown = new Countdown(); CountdownThread t1 = new CountdownThread(countdown);
t1.setName("Thread 1");
CountdownThread t2 = new CountdownThread(countdown);
t2.setName("Thread 2");
t1.start();
t2.start();
}
}
class Countdown {
private int i;
public void doCountdown() {
String color;
switch (Thread.currentThread().getName()) {
case "Thread 1":
color = ThreadColor.ANSI_CYAN;
break;
case "Thread 2":
color = ThreadColor.ANSI_PURPLE;
break;
default:
color = ThreadColor.ANSI_GREEN;
}
synchronized (this) {
for (i = 10; i > 0; i--) {
System.out.println(color + Thread.currentThread().getName() + ": i=" + i);
}
}
}
}
class CountdownThread extends Thread {
private Countdown threadCountdown;
public CountdownThread(Countdown countdown) {
this.threadCountdown = countdown;
}
@Override
public void run() {
threadCountdown.doCountdown();
}
}

輸出結果:

Thread 1: i=10

Thread 1: i=9

Thread 1: i=8

Thread 1: i=7

Thread 1: i=6

Thread 1: i=5

Thread 1: i=4

Thread 1: i=3

Thread 1: i=2

Thread 1: i=1

Thread 2: i=10

Thread 2: i=9

Thread 2: i=8

Thread 2: i=7

Thread 2: i=6

Thread 2: i=5

Thread 2: i=4

Thread 2: i=3

Thread 2: i=2

Thread 2: i=1

這是第二種 Synchronisation 的用法

對 statement 做 synchronisation

但要特別注意使用的變量

這裡就滿困難的

看了討論區很多的 QA ,我還是霧沙沙

關鍵全部的 Thread 都要能訪問到同一個變量

變量的篩選要特別注意

補充資料:Synchronized Methods

java syntax: “synchronized (this)”

上面代碼全都紀錄在我的 Github

--

--

張小雄
張小雄

Written by 張小雄

記錄成為軟體工程師的過程

No responses yet