1. 程式人生 > >java中同步方式--synchronized

java中同步方式--synchronized

執行緒安全,是指每次執行結果和單執行緒執行的結果是一樣的,而且其他的變數的值也和預期的是一樣的。或者說:一個類或者程式所提供的介面對於執行緒來說是原子操作或者多個執行緒之間的切換不會導致該介面的執行結果存在二義性,也就是說我們不用考慮同步的問題。

執行緒安全問題都是由全域性變數及靜態變數引起的,若每個執行緒中對全域性變數、靜態變數只有讀操作,而無寫操作,一般來說,這個全域性變數是執行緒安全的;若有多個執行緒同時執行寫操作,一般都需要考慮執行緒同步,否則就可能影響執行緒安全

synchronized

java語言的關鍵字,修飾一個方法或者一個程式碼塊的時候,能夠保證在同一時刻最多隻有一個執行緒執行該段程式碼。 

1.當2個併發執行緒訪問同一個物件object中的這個synchronized(this)同步程式碼塊的時,一個執行緒得到執行,另一個執行緒必須等待當前執行緒執行完這個程式碼塊以後才能執行該程式碼塊 2.當一個執行緒訪問object的一個synchronized(this)同步程式碼時,另外一個執行緒仍然可以訪問非synchronized(this)同步程式碼塊 3.當一個執行緒訪問object的一個synchronized(this)同步程式碼塊時,其他執行緒對object中所synchronized(this)同步程式碼塊的訪問也將阻塞 4.當一個執行緒訪問objetc的一個synchroniized(this)同步程式碼塊時,它就獲得了這個object,其他執行緒對該object物件所有同步程式碼部分的訪問都被暫時阻塞
5.以上規則對其他物件鎖同樣適用 Synchronized應用舉例 1.當兩個併發執行緒訪問同一個物件object中的這個synchronized(this)同步程式碼時,一個一個執行緒得到執行,另外一個執行緒必須等到當前執行緒執行完這個程式碼塊以後才能執行該程式碼塊 public class Thread1 implements Runnable{ public void run(){ synchronized(this){ for(int i=0;i<5;i++){ System.out.println() } } }
  1.      publicstaticvoid main(String[] args) {   
  2.           Thread1 t1 = new Thread1();   
  3.           Thread ta = new Thread(t1, "A");   
  4.           Thread tb = new Thread(t1, "B");   
  5.           ta.start();   
  6.           tb.start();   
  7.      } 

} 執行結果: 

     A synchronized loop 0 
     A synchronized loop 1 
     A synchronized loop 2 
     A synchronized loop 3 
     A synchronized loop 4
 
     B synchronized loop 0 
     B synchronized loop 1 
     B synchronized loop 2 
     B synchronized loop 3 
     B synchronized loop 4

2、然而,當一個執行緒訪問object的一個synchronized(this)同步程式碼塊時,另一個執行緒仍然可以訪問該object中的非synchronized(this)同步程式碼塊。

程式碼示例:

[java] view plaincopyprint?
  1. publicclass Thread2 {   
  2.      publicvoid m4t1() {   
  3.           synchronized(this) {   // 同步
  4.                int i = 5;   
  5.                while( i-- > 0) {   
  6.                     System.out.println(Thread.currentThread().getName() + " : " + i);   
  7.                     try {   
  8.                          Thread.sleep(500);   
  9.                     } catch (InterruptedException ie) {   
  10.                     }   
  11.                }   
  12.           }   
  13.      }   
  14.      publicvoid m4t2() {   
  15.           int i = 5;   // 非同步
  16.           while( i-- > 0) {   
  17.                System.out.println(Thread.currentThread().getName() + " : " + i);   
  18.                try {   
  19.                     Thread.sleep(500);   
  20.                } catch (InterruptedException ie) {   
  21.                }   
  22.           }   
  23.      }   
  24.      publicstaticvoid main(String[] args) {   
  25.           final Thread2 myt2 = new Thread2();   
  26.           Thread t1 = new Thread(  new Runnable() {  publicvoid run() {  myt2.m4t1();  }  }, "t1"  );   
  27.           Thread t2 = new Thread(  new Runnable() {  publicvoid run() { myt2.m4t2();   }  }, "t2"  );   
  28.           t1.start();   
  29.           t2.start();   
  30.      }  
  31. }  
執行結果: 

     t1 : 4 
     t2 : 4 
     t1 : 3 
     t2 : 3 
     t1 : 2 
     t2 : 2 
     t1 : 1 
     t2 : 1 
     t1 : 0 
     t2 : 0

尤其關鍵的是,當一個執行緒訪問object的一個synchronized(this)同步程式碼塊時,其他執行緒對object中所有其它synchronized(this)同步程式碼塊的訪問將被阻塞。

程式碼示例:

[java] view plaincopyprint?
  1. //修改Thread2.m4t2()方法: 
  2. publicvoid m4t2() {   
  3.     synchronized(this) {   // 同步
  4.           int i = 5;   
  5.           while( i-- > 0) {   
  6.                System.out.println(Thread.currentThread().getName() + " : " + i);   
  7.                try {   
  8.                     Thread.sleep(500);   
  9.                } catch (InterruptedException ie) {   
  10.                }   
  11.           }   
  12.      }  
  13. }  
執行結果:

     t1 : 4 
     t1 : 3 
     t1 : 2 
     t1 : 1 
     t1 : 0 

     t2 : 4 
     t2 : 3 
     t2 : 2 
     t2 : 1 
     t2 : 0

4、第三個例子同樣適用其它同步程式碼塊。也就是說,當一個執行緒訪問object的一個synchronized(this)同步程式碼塊時,它就獲得了這個object的物件鎖。結果,其它執行緒對該object物件所有同步程式碼部分的訪問都被暫時阻塞。

程式碼示例:

[java] view plaincopyprint?
  1. //修改Thread2.m4t2()方法如下:
  2. publicsynchronizedvoid m4t2() {  // 同步程式碼塊(同步方法)
  3.      int i = 5;   
  4.      while( i-- > 0) {   
  5.           System.out.println(Thread.currentThread().getName() + " : " + i);   
  6.           try {   
  7.                Thread.sleep(500);   
  8.           } catch (InterruptedException ie) {   
  9.           }   
  10.      }   
  11. }  
執行結果: 

     t1 : 4 
     t1 : 3 
     t1 : 2 
     t1 : 1 
     t1 : 0 

     t2 : 4 
     t2 : 3 
     t2 : 2 
     t2 : 1 
     t2 : 0

5.以上規則對其他物件鎖同樣適用: 程式碼示例:
  1. publicclass Thread3{  
  2.      class Inner {  
  3.           privatevoid m4t1() {  
  4.                int i = 5;  
  5.                while(i-- > 0) {  
  6.                     System.out.println(Thread.currentThread().getName() + " : Inner.m4t1()=" + i);  
  7.                     try {  
  8.                          Thread.sleep(500);  
  9.                     } catch(InterruptedException ie) {  
  10.                     }  
  11.                }  
  12.           }  
  13.           privatevoid m4t2() {  
  14.                int i = 5;  
  15.                while(i-- > 0) {  
  16.                     System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i);  
  17.                     try {  
  18.                          Thread.sleep(500);  
  19.                     } catch(InterruptedException ie) {  
  20.                     }  
  21.                }  
  22.           }  
  23.      }  
  24.      privatevoid m4t1(Inner inner) {  
  25.           synchronized(inner) { //使用物件鎖
  26.           inner.m4t1();  
  27.      }  
  28.      privatevoid m4t2(Inner inner) {  
  29.           inner.m4t2();  
  30.      }  
  31.      publicstaticvoid main(String[] args) {  
  32.           final Thread3 myt3 = new Thread3();  
  33.           final Inner inner = myt3.new Inner();  
  34.           Thread t1 = new Thread( new Runnable() {publicvoid run() { myt3.m4t1(inner);} }, "t1");  
  35.           Thread t2 = new Thread( new Runnable() {publicvoid run() { myt3.m4t2(inner);} }, "t2");  
  36.      t1.start();  
  37.      t2.start();  
  38.   }  
  39. }  
執行結果:

儘管執行緒t1獲得了對Inner的物件鎖,但由於執行緒t2訪問的是同一個Inner中的非同步部分。所以兩個執行緒互不干擾。

     t1 : Inner.m4t1()=4 
     t2 : Inner.m4t2()=4 
     t1 : Inner.m4t1()=3 
     t2 : Inner.m4t2()=3 
     t1 : Inner.m4t1()=2 
     t2 : Inner.m4t2()=2 
     t1 : Inner.m4t1()=1 
     t2 : Inner.m4t2()=1 
     t1 : Inner.m4t1()=0 
     t2 : Inner.m4t2()=0

現在在Inner.m4t2()前面加上synchronized:

[java] view plain

相關推薦

java同步方式--synchronized

執行緒安全,是指每次執行結果和單執行緒執行的結果是一樣的,而且其他的變數的值也和預期的是一樣的。或者說:一個類或者程式所提供的介面對於執行緒來說是原子操作或者多個執行緒之間的切換不會導致該介面的執行結果存在二義性,也就是說我們不用考慮同步的問題。 執行緒安全問題都是由全

java同步synchronized的意義,如何用它解決執行緒不安全的問題

馬克-to-win:從上節我們學到,當多個執行緒訪問且更改同一個變數時,很容易出現執行緒安全問題,誠然,我們可以通過一些其他手段,比如區域性變數,多個例項,調整程式結構來解決執行緒安全問題,但是通常來講,通過同步機制s

java同步(synchronized)訪問共享的可變資料及原子性操作

當多個執行緒共享可變資料的時候,每個讀或者寫資料的執行緒都必須執行同步。如果沒有同步,就無法保證一個執行緒所做的修改可以被另外一個執行緒獲知。未能同步共享可變資料會造成程式的活性失敗(liveness failure)和安全性失敗(safety failure)

javavolatile、synchronized

htm mic eight 完成 安全問題 strong 跳過 ring 變量定義 先補充一下概念:Java 內存模型中的可見性、原子性和有序性。 可見性:   可見性是一種復雜的屬性,因為可見性中的錯誤總是會違背我們的直覺。通常,我們無法確保執行讀操作的線程能適時地看到其

JavaVolatile和Synchronized的區別

個人部落格:小景哥哥 Java中Volatile和Synchronized的區別 JMM Java Memory Model. 併發過程中如何處理可見性、原子性、有序性的問題 Runnable、Thread 併發程式設計中的兩個關鍵問題 a.執行緒之間如何通訊 wai

Java同步非同步區別

同步互動:指傳送一個請求,需要等待返回。然後才能傳送下一個請求,有等待過程; 非同步互動:指傳送一個請求,不需要等待返回,隨時可以在傳送下一個請求,不需要等待; 區別:一個需要等待,一個不需要等待,在部分情況下,我們的專案開發中都會優先選擇不需要等待的非同步互動方式; Java是一門面向物件

javavolatile和synchronized

JMM java Memory Model 併發過程中如何處理可見性,原子性,有序性的問題 併發過程中兩個關鍵性的問題 a 執行緒之間如何通訊:wait() notify() notifall() a)共享記憶體 - 隱式通訊 b) 訊息傳遞 - 顯示通訊 b 執行緒之間如

Java的關鍵字synchronized

1. 介紹 在Java併發系列的文章中,這個是第二篇文章。在前面的一篇文章中,我們學習了Java中的Executor池和Excutors的各種類別。 在這篇文章中,我們會學習synchronized關鍵字以及我們在多執行緒的環境中如何使用。 2. 什麼是同步? 在一個多執行緒的環境中,多個執行緒同時訪

【高併發】面試官:Java提供了synchronized,為什麼還要提供Lock呢?

## 寫在前面 > 在Java中提供了synchronized關鍵字來保證只有一個執行緒能夠訪問同步程式碼塊。既然已經提供了synchronized關鍵字,那為何在Java的SDK包中,還會提供Lock介面呢?這是不是重複造輪子,多此一舉呢?今天,我們就一起來探討下這個問題。 ## 再造輪子? 既

java的兩種同步方式Synchronized與ReentrantLock的區別

性能 避免 字節碼 數據 獲取對象 通過 finall 內核 構造函數 java在編寫多線程程序時,為了保證線程安全,需要對數據同步,經常用到兩種同步方式就是Synchronized和重入鎖ReentrantLock。 相似點: 這兩種同步方式有很多相似之

深入理解Java同步靜態方法和synchronized(class)程式碼塊的類鎖 深入理解Java併發synchronized同步化的程式碼塊不是this物件時的操作

一.回顧學習內容  在前面幾篇部落格中我我們已經理解了synchronized物件鎖、物件鎖的重入、synchronized方法塊、synchronized非本物件的程式碼塊,  連結:https://www.cnblogs.com/SAM-CJM/category/1314992.h

Javasynchronized同步方法

在多執行緒中,有一個經典問題:存票售票問題 如果只用兩個Thread子類則容易陷入死迴圈。 有一個很好的解決辦法就是synchronized。 方法一:在thread子類的run中直接通過synchronized來申請物件的鎖旗標,即用synchronized把存售票程式碼框起來。 方法二:在票類中直

深入理解Java同步靜態方法和synchronized(class)程式碼塊的類鎖

一.回顧學習內容  在前面幾篇部落格中我我們已經理解了synchronized物件鎖、物件鎖的重入、synchronized方法塊、synchronized非本物件的程式碼塊,  我們來總結一下,上面幾篇講到內容:  1.建立執行緒類的兩個方式:繼承Thread類和實現Runable介面。  2.瞭解了Th

java執行緒同步Synchronized,監視器monitor和鎖lock的關係是什

既然有關監視器monitor的概念比較難,大家怎麼解釋的都有。首先我給出一下java的官方文件,也是最權威的解釋: Synchronizationis built around an internal entity known as the intrinsic lock ormonitor lock. (Th

Java建立執行緒的幾種方式以及執行緒同步的幾種方式

執行緒同步自己及基本就用過Thread和Runnable這兩種方式,還有其他很多方式如下: Executor框架簡介 建立執行緒有幾種不同的方式?你喜歡哪一種?為什麼? 而執行緒同步會用的方式就更少了,只會synchronized,其他方式如下: 關於執

java 為什麼wait(),notify(),notifyAll()必須在同步Synchronized)方法/程式碼塊呼叫?

先回答問題: (1)為什麼wait()必須在同步(Synchronized)方法/程式碼塊中呼叫? 答:呼叫wait()就是釋放鎖,釋放鎖的前提是必須要先獲得鎖,先獲得鎖才能釋放鎖。 (2)為什麼notify(),notifyAll()必須在同步(Synchronize

javasynchronized同步程式碼塊和同步方法的區別

問題的由來: 看到這樣一個面試題: //下列兩個方法有什麼區別 public synchronized void method1(){} public void method2(){ synchronized (obj){} } synchronized用

javasynchronized修飾程式碼塊(兩種建立執行緒的方式講解賣票程式)

格式: synchronized(類物件名 aa) { //同步程式碼塊 } 功能: synchronized(類物件名 aa)的含義是:判斷aa是否已經被其他執行緒所霸佔,如果發現已經被其他執行緒霸

java的執行緒同步實現方法一(將方法設定為synchronized

一. 簡要說明:  對於java中的執行緒同步來說,可以用synchronized關鍵字來修飾,既可以對方法進行修飾,也可以對變數進行修飾,而二者都可以實現執行緒的同步。本篇說的是第一種方法,第二種方法在下一篇中說明。 二. 例子:     AccountRunnable.

Java實現執行緒同步的幾種常用方式

首先講一下為什麼要實現執行緒同步: java允許多執行緒併發控制,當多個執行緒同時操作一個可共享的資源變數時(如資料的增刪改查),  將會導致資料不準確,相互之間產生衝突,因此加入同步鎖以避免在該執行緒沒有完成操作之前,被其他執行緒的呼叫, 從而保證了該變數的唯一性和準