多線程同步中的門道(二)
前言
在涉及到多線程的開發時,線程同步的考慮是不可缺少的,否則很可能會造成各種超出預料的錯誤結果。以自己的學習經歷來說,對於剛開始接觸線程同步的人可能會感覺非常簡單,在多線程操作可能會造成數據混亂的地方同步一下不就行了嘛,加個synchronized關鍵字,多簡單!可是隨着開發的深入,會漸漸的發現僅僅是一個synchronized關鍵字也不是那么簡單,里面的門道和考慮到的情況還是不少。本系列就着循序漸進的程序和大家探討一下synchronized關鍵字使用中的各種情形和會造成的各種意料之外和意料之中的結果,歡迎各位大神輕拍。
轉載請注明本文地址:http://www.cnblogs.com/hellojava/p/3635336.html
系列文章:多線程同步中的門道(一)
synchronized涉及到同步方法、同步代碼塊、同步類、同步對象、靜態方法等,本系列來挨個探討。
注:因為考慮到文章篇幅和為了突出我們要分析的關鍵代碼,所以下面程序有可能不會是最優寫法。
同步代碼塊
同步代碼塊,分為同步對象和同步類兩種,下面我們來挨個介紹。
同步對象
我們首先來看看一個同步對象的例子。
[測試程序4.1]
/** * Test case 4.1. synchronized code block.synchronized object. */
public class Test { public static void main(String[] args) { // The same object.
final TestCase test1 = new TestCase(); // final TestCase test2 = new TestCase();
Thread thread1 = new Thread() { @Override public void run() { test1.function(); } }; Thread thread2 = new Thread() { @Override public void run() { test1.function(); } }; thread2.start(); thread1.start(); } } class TestCase { public void function() { // synchronized object.
synchronized (this) { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + " executed result: " + i); } } } }
程序中使用了同步代碼塊,同步的是對象。把function中的方法全部給包括起來了,這樣進入這個方法的線程會被同步。注意上面main測試程序中兩個線程調用的都是同一個對象的function方法。
運行程序,始終會得到如下結果:
Thread-1 executed result: 0 Thread-1 executed result: 1 Thread-1 executed result: 2 Thread-1 executed result: 3 Thread-1 executed result: 4 Thread-0 executed result: 0 Thread-0 executed result: 1 Thread-0 executed result: 2 Thread-0 executed result: 3 Thread-0 executed result: 4
從運行結果可以看出,兩個線程順序執行。這就意味着對一個對象的同步是成功的,當一個線程進入這個對象的function方法中的同步代碼塊時,就鎖住了這個對象,第二個線程在想進入這個同步代碼塊時,就要等待第一個線程執行完同步代碼塊或拋出異常。
但是先別急,我們來看看對不同對象是否還會起作用。
[測試程序4.2]
/** * Test case 4.2. synchronized code block.synchronized object. */
public class Test { public static void main(String[] args) { // The different objects.
final TestCase test1 = new TestCase(); final TestCase test2 = new TestCase(); Thread thread1 = new Thread() { @Override public void run() { test1.function(); } }; Thread thread2 = new Thread() { @Override public void run() { test2.function(); } }; thread2.start(); thread1.start(); } } class TestCase { public void function() { // synchronized object.
synchronized (this) { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + " executed result: " + i); } } } }
對4.1的程序稍作修改,演變成了4.2程序。兩個程序的區別就是兩個線程分別調用了TestCase類的兩個不同的對象的function方法。
執行程序,某次運行結果如下所示:
Thread-1 executed result: 0 Thread-1 executed result: 1 Thread-1 executed result: 2 Thread-0 executed result: 0 Thread-0 executed result: 1 Thread-0 executed result: 2 Thread-0 executed result: 3 Thread-1 executed result: 3 Thread-0 executed result: 4 Thread-1 executed result: 4
在同步代碼塊中,對對象的同步,當兩個線程使用不同的對象時,就不會順序執行了,而是交叉執行。說明同步不了不同的對象。
同步小結
在同步代碼塊中,對對象同步時
- 使用同步對象相當於對對象上鎖;
- 當一個線程進入同步的代碼塊時,對當前對象上鎖,別的線程無法進入這個對象的同步代碼,但是可以進入別的對象的方法;
- 這種同步對象的方式無法放在靜態方法中。
同步類
上面同步對象的方式無法對不同的對象作線程同步,我們就來同步類看看。
[測試程序5.1]
/** * Test case 5.1. synchronized code block.synchronized class. */
public class Test { public static void main(String[] args) { // The different objects.
final TestCase test1 = new TestCase(); final TestCase test2 = new TestCase(); Thread thread1 = new Thread() { @Override public void run() { test1.function(); } }; Thread thread2 = new Thread() { @Override public void run() { test2.function(); } }; thread2.start(); thread1.start(); } } class TestCase { public void function() { // synchronized class.
synchronized (TestCase.class) { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + " executed result: " + i); } } } }
上面的程序,在同步代碼塊那里,可以看出是對類進行同步。並且兩個線程是分別執行兩個不同對象的function方法。
運行一下,總是輸出結果:
Thread-1 executed result: 0 Thread-1 executed result: 1 Thread-1 executed result: 2 Thread-1 executed result: 3 Thread-1 executed result: 4 Thread-0 executed result: 0 Thread-0 executed result: 1 Thread-0 executed result: 2 Thread-0 executed result: 3 Thread-0 executed result: 4
兩個線程順序執行,可以看出,當同步類的時候,即便是不同的線程執行了這個類的不同對象,線程之間也是同步的。至於其他情形,可以自己做測試用例來驗證。
同步類小結
在同步代碼塊中,同步類是對類上鎖。當一個線程進入了同步代碼塊,就對類上鎖,其他線程無法進入這個類的其他對象的同步方法。
