多線程同步中的門道(二)html
前言java
在涉及到多線程的開發時,線程同步的考慮是不可缺乏的,不然極可能會形成各類超出預料的錯誤結果。以本身的學習經從來說,對於剛開始接觸線程同步的人可能會感受很是簡單,在多線程操做可能會形成數據混亂的地方同步一下不就好了嘛,加個synchronized關鍵字,多簡單!但是隨着開發的深刻,會漸漸的發現僅僅是一個synchronized關鍵字也不是那麼簡單,裏面的門道和考慮到的狀況仍是很多。本系列就着按部就班的程序和你們探討一下synchronized關鍵字使用中的各類情形和會形成的各類意料以外和意料之中的結果,歡迎各位大神輕拍。多線程
轉載請註明本文地址:http://www.cnblogs.com/hellojava/p/3635336.html
ide
系列文章:多線程同步中的門道(一)學習
synchronized涉及到同步方法、同步代碼塊、同步類、同步對象、靜態方法等,本系列來挨個探討。測試
注:由於考慮到文章篇幅和爲了突出咱們要分析的關鍵代碼,因此下面程序有可能不會是最優寫法。this
同步代碼塊spa
同步代碼塊,分爲同步對象和同步類兩種,下面咱們來挨個介紹。線程
同步對象code
咱們首先來看看一個同步對象的例子。
[測試程序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
兩個線程順序執行,能夠看出,當同步類的時候,即使是不一樣的線程執行了這個類的不一樣對象,線程之間也是同步的。至於其餘情形,能夠本身作測試用例來驗證。
同步類小結
在同步代碼塊中,同步類是對類上鎖。當一個線程進入了同步代碼塊,就對類上鎖,其餘線程沒法進入這個類的其餘對象的同步方法。