全部對象都自動含有單一的鎖,也就是全部對象都有且只有惟一的鎖,因此當某個任務(線程)訪問一個類A中含有sycnhronized的方法是,那麼在這個線程從該方法返回以前(也就是該方法在當前線程執行完以前),類A中的其餘被該關鍵字標記的方法在其餘的線程中都會被阻塞。
通俗點說就是,當調用A的含有synchronized的方法是,A會被枷鎖,此時A中其餘含有synchronized方法只有等到前一個方法調用完畢釋放了鎖才能被調用
具體說明見另外一篇博客<<java同步和互斥【相關原理】》html
下面看看具體的程序,其中,Timer中的字段num是共享資源java
- package com.bankht.synchronize;
-
- public class TestSync implements Runnable {
- Timer timer = new Timer();
-
- public static void main(String[] args) {
- TestSync test = new TestSync();
- Thread t1 = new Thread(test);
- Thread t2 = new Thread(test);
- t1.setName("t1");
- t2.setName("t2");
- t1.start();
- t2.start();
- }
-
- public void run() {
- timer.add(Thread.currentThread().getName());
- }
- }
-
- class Timer {
- private static int num = 0;
-
- public void add(String name) {
-
- num++;
- try {
- Thread.sleep(1);
- } catch (InterruptedException e) {
- }
- System.out.println(name + ", 你是第" + num + "個使用timer的線程");
-
- }
- }
t1, 你是第2個使用timer的線程post
t2, 你是第2個使用timer的線程this
也就是說當線程一運行到num++的時候被打線程2打斷了,因爲java中遞增和遞減操做均不是原子操做,因此本程序中即便沒有調用sleep,也會出現這種被打斷的狀況spa
下面看看同步的效果.net
- public void add(String name) {
- synchronized (this) {
- num++;
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- }
- System.out.println(name + ", 你是第" + num + "個使用timer的線程");
- }
- }
這樣運行結果就會出是正確的線程
t1, 你是第1個使用timer的線程htm
t2, 你是第2個使用timer的線程對象
可是,下面爲了說明問題把TestSync裏面的run方法改爲以下所示blog
- public void run() {
- /
- time.add(Thread.currentThread().getName());
- try {
- Thread.sleep(1000);
- } catch (InterruptedException ex) {
- Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);
- }
- System.out.println(Thread.currentThread().getName() + "----");
- }
那麼在此運行就是
t1, 你是第1個使用timer的線程
t2, 你是第2個使用timer的線程
t1--------
t2--------
而不是你所想象的
t1, 你是第1個使用timer的線程
t1----
t2, 你是第2個使用timer的線程
t2----
緣由就是在線程t1在睡眠的時候,線程t2切換進來,執行了一次,怎樣獲得正確的結果呢,下面把TestSync裏面的run方法作以下改進就能夠獲得上面預期的結果
- public void run() {
- synchronized(time){
- time.add(Thread.currentThread().getName());
- try {
- Thread.sleep(3000);
- } catch (InterruptedException ex) {
- Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);
- }
- System.out.println(Thread.currentThread().getName() + "----");
- }
- }
由於t1先得到time的鎖,因此在執行完run裏面的同步塊以前,即便sleep(),t2也不會執行,由於t2沒有得到time的鎖,且sleep()操做也不釋放鎖(這也是和wait的巨大區別)
附錄:TestSync.java所有代碼
- package com.bankht.synchronize;
-
- import java.util.logging.Level;
- import java.util.logging.Logger;
-
- public class TestSync implements Runnable {
- Timer timer = new Timer();
-
- public static void main(String[] args) {
- TestSync test = new TestSync();
- Thread t1 = new Thread(test);
- Thread t2 = new Thread(test);
- t1.setName("t1");
- t2.setName("t2");
- t1.start();
- t2.start();
- }
-
-
-
- public void run() {
- synchronized(timer){
- timer.add(Thread.currentThread().getName());
- try {
- Thread.sleep(3000);
- } catch (InterruptedException ex) {
- Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);
- }
- System.out.println(Thread.currentThread().getName() + "----");
- }
- }
- }
-
- class Timer {
- private static int num = 0;
-
-
- public void add(String name) {
- synchronized (this) {
- num++;
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- }
- System.out.println(name + ", 你是第" + num + "個使用timer的線程");
- }
- }
-
-
- }