在Java多執行緒中,可使用synchronized
關鍵字用來宣告一個method或一段程式區塊為同步。同步的意思是,在同步方法/區塊/成員變數中一次只允許一條執行緒存取被鎖定的物件。
例如下面範例t1
及t2
執行緒的run()
方法中皆宣告了同步區塊,鎖定對象是傳入synchronized
的pl
物件,因此一次只會有一條執行緒(t1
or t2
)存取pl
物件。
public class Main {
public static void main(String[] args) throws InterruptedException {
PrintLoop pl = new PrintLoop();
Thread t1 = new Thread("t1") {
@Override
public void run() {
String threadName = Thread.currentThread().getName();
synchronized (pl) {
System.out.println(threadName + ":同步開始");
pl.print(threadName, 5);
System.out.println(threadName + ":同步結束");
}
}
};
Thread t2 = new Thread("t2") {
@Override
public void run() {
String threadName = Thread.currentThread().getName();
synchronized (pl) {
System.out.println(threadName + ":同步開始");
pl.print(threadName, 5);
System.out.println(threadName + ":同步結束");
}
}
};
t1.start();
t2.start();
}
}
class PrintLoop {
public void print(String threadName, int times) {
System.out.println(threadName + ":print開始");
for (int i = 0; i < times; i++) {
System.out.println(threadName + ":" + i);
}
System.out.println(threadName + ":print結束");
}
}
執行結果可能如下
t1:同步開始
t1:print開始
t1:0
t1:1
t1:2
t1:3
t1:4
t1:print結束
t1:同步結束
t2:同步開始
t2:print開始
t2:0
t2:1
t2:2
t2:3
t2:4
t2:print結束
t2:同步結束
如果把run()
中的同步區塊移除,則pl
將不被鎖定,可允許多個執行緒同時存取。
public class Main {
public static void main(String[] args) throws InterruptedException {
PrintLoop pl = new PrintLoop();
Thread t1 = new Thread("t1") {
@Override
public void run() {
String threadName = Thread.currentThread().getName();
// synchronized (pl) {
System.out.println(threadName + ":同步開始");
pl.print(threadName, 5);
System.out.println(threadName + ":同步結束");
// }
}
};
Thread t2 = new Thread("t2") {
@Override
public void run() {
String threadName = Thread.currentThread().getName();
// synchronized (pl) {
System.out.println(threadName + ":同步開始");
pl.print(threadName, 5);
System.out.println(threadName + ":同步結束");
// }
}
};
t1.start();
t2.start();
}
}
class PrintLoop {
public void print(String threadName, int times) {
System.out.println(threadName + ":print開始");
for (int i = 0; i < times; i++) {
System.out.println(threadName + ":" + i);
}
System.out.println(threadName + ":print結束");
}
}
則執行結果可能如下。
t1:同步開始
t2:同步開始
t1:print開始
t2:print開始
t1:0
t2:0
t1:1
t2:1
t1:2
t1:3
t1:4
t1:print結束
t2:2
t1:同步結束
t2:3
t2:4
t2:print結束
t2:同步結束
比較以上兩種不同的結果可觀察到有同步和沒同步的差異。在同步區塊中,被鎖定的物件只能被一條執行緒存取,直到執行緒離開同步區塊後才會釋放該物件的鎖,接著另一條執行緒才能取得鎖並存取該物件。
沒有留言:
張貼留言