Synchronized不一定是執行緒安全的吧?_wait釋放同步鎖
在做併發開發的時候,為了保證某物件的執行緒安全,一般都會對其用Synchronized進行保護,比如:
synchronized(obj) {
// Do something with obj.
}
當所有對obj進行的操作,都用同步塊保護時,我們一般認為其是執行緒安全的。
但這個執行緒安全到底有多安全呢?請先看看這個簡單的例子:
程式碼實現很簡單,兩個執行緒同時修改一個物件的屬性,在其屬性原值基礎上進行計算,然後再回寫;
但是這裡面故意使用了 obj.wait(),實際上造成對synchronized同步鎖的釋放。
public class synchronizedWrongUse {
public static void main(String[] args) throws Exception{
//初始化
SomeoneObject obj = new SomeoneObject();
Worker a = new Worker("A", obj);
Worker b = new Worker("B", obj);
//啟動執行緒
a.start();
b.start();
//等待執行緒啟動
Thread.sleep(100);
//喚醒obj
synchronized(obj){
obj.notifyAll();
System.out.println("notifyAll done.");
}
//等待執行緒結束
a.join();
b.join();
//輸出結果
System.out.println("Amount:"+obj.getAmount());//只有50
}
static class Worker extends Thread{
private SomeoneObject obj;
public Worker(String name,SomeoneObject obj){
super(name);
this.obj = obj;
}
public void run(){
System.out.println("Worker["+this.getName()+"]started.");
synchronized(obj){//為保證obj操作的互斥性,加同步鎖,但是wait釋放了同步鎖
int amount = obj.getAmount();
amount += 50;
// try{
// obj.wait();//這裡wait釋放了同步鎖
// }catch(InterruptedException e){
// return;
// }
obj.setAmount(amount);
System.out.println("Worker["+this.getName()+"]setting done.");
}
}
}
/**
* @author lix
*某物件
*/
static class SomeoneObject{
int amount;//屬性
public int getAmount(){
return amount;
}
public void setAmount(int amount){
this.amount = amount;
}
}
}
兩個執行緒各 +50,期望結果是100;但實際結果仍然只有50。
接觸過事務的人應該能很快理解,在synchronized塊中,未必能絕對保證事務一致性;因為wait釋放了同步鎖。
當然,避免這種情況發生一般來說也很簡單:
1、儘量不要將基於原有狀態的計算過程被中斷,也就是你別在 amount += 50; 中間插入wait;
2、可以做樂觀檢查,也就是set之前重新檢查下當前狀態是否與原狀態保持一致,不一致就要重新發起計算。
相關推薦
Synchronized不一定是執行緒安全的吧?_wait釋放同步鎖
在做併發開發的時候,為了保證某物件的執行緒安全,一般都會對其用Synchronized進行保護,比如: synchronized(obj) { // Do something with obj. } 當所有對obj進行的操作,都用同步塊保護時,我們
java.text.DateFormat類的format(),parse()等方法不是執行緒安全的,所以一定不要把此變數定義成全域性的靜態變數
在使用:java.text.DateFormat類時,請注意他的format(),parse()等方法不是執行緒安全的,一定不要把此變數定義成全域性的靜態變數,否在在多執行緒的併發環境裡會發生你意想不到的錯誤!!! 例如,不要定義成一下樣子: public static fi
struts2的action是執行緒安全的,struts1的action不是執行緒安全的真正原因
為什麼struts2的action是執行緒安全的,struts1的action不是執行緒安全的? 先對struts1和struts2的原理做一個簡單的講解 對於struts1 ,當第一次**.do的請求過來時,在記憶體中的actionmapping中找到相對應的action,然後new出
併發下HashMap為什麼不是執行緒安全的?
首先看下HashMap的工作原理,我們回顧一下HashMap的結構: HashMap的結構就是雜湊表,底層是一個數組,這個陣列中儘可能地分散所有的key,通過key的hash值得到陣列下標,然後把entry插到該陣列
第100次提醒:++ 不是執行緒安全的
目錄 寫在前面 一道簡單執行緒安全題,不知道有多少人答不上來 實驗:併發的自增運算 ++ 運算的原理 Java 的原子操作類 寫在最後 瘋狂創客圈 Java 死磕系列 瘋狂創客圈 Java 分散式聊天室【 億級流量】實戰系列之 -17【 部落格園 總入口 】 原始
為什麼volatile關鍵字保證不了執行緒安全
在當前高併發的時代,不懂一點高併發多執行緒都不好意思出去,即使沒地方使用,網上大多數相關文件部落格也都講解了這些部分。 我並不想具體介紹什麼是volatile,我寫這篇部落格目的是說明白為什麼vo
HashMap為什麼不是執行緒安全的?
HashMap底層是一個Entry陣列,當發生hash衝突的時候,hashmap是採用連結串列的方式來解決的,在對應的陣列位置存放連結串列的頭結點。對連結串列而言,新加入的節點會從頭結點加入。 javadoc中關於hashmap的一段描述如下: 此實現不是同步的。如果多個執行緒同時訪
第101次提醒:++ 操作不是執行緒安全的!
瘋狂創客圈 Java 分散式聊天室【 億級流量】實戰系列之 -20【 部落格園 總入口 】 文章目錄 寫在前面 一道簡單執行緒安全題,不知道有多少人答不上來 實驗:併發的自增運算 ++ 運算的原理 Java 的原子操
區域性變數一定執行緒安全嗎
區域性變數, 如果是基本型別或是包裝型別, 依然不能通過多執行緒改變其值, 如果是物件, 則其屬性值是執行緒不安全的 demo1: public void compute(LocalDate date){ //在切換租戶時,只有當前執行緒的第一個租戶id
Android Studio——為什麼說android UI操作不是執行緒安全的
可能在非UI執行緒中重新整理介面的時候,UI執行緒(或者其他非UI執行緒)也在重新整理介面,這樣就導致多個介面重新整理的操作不能同步,導致執行緒不安全。 1、為什麼說invalidate()不能直接線上程中呼叫? 2、它是怎麼違背單執行緒的? 3、android ui為
servlet為什麼不是執行緒安全的?
因為servlet是多執行緒的,而servlet的生命週期又web容器進行管理(Tomcat)。當客服端對servlet第一次進行請求時候,伺服器(tomcat)會對根據web.xml檔案進行例項化這個serlvet(所以web.xml中不能出現任何錯誤)。當用戶再對該ser
對於Hibernate的openSession方法為什麼不是執行緒安全的原始碼理解
首先,先明確幾個概念。 1、區域性變數不會受多執行緒影響。 2、成員變數會受到多執行緒影響。 多個執行緒呼叫的同一個物件的同一個方法: 如果方法裡無成員變數,不受任何影響, 如果方法裡有成員變數,只有讀操作,不受影響,存在賦值操作,有影響。 第一點
多執行緒安全問題之Lock顯示鎖
package com.hls.juc;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/** * 解決多執行緒安全問題的方式: 3種 * synchronized: 隱式鎖 * 1.
執行緒安全的實現方式和鎖優化
什麼是執行緒安全? 在Java中執行緒安全的場景有哪些? 不可變 絕對執行緒安全 相對執行緒安全 執行緒相容 執行緒對立 Java中保證執行緒安全的方式? 互斥同步 非阻塞同步 無同步方案 1. 可重入程式碼 2. 執行緒本地儲存
多執行緒安全問題解決之顯示鎖Lock
【1】顯示鎖和隱式鎖 在Java 5.0 之前,協調共享物件的訪問時可以使用的機制只有synchronized 和volatile 。Java 5.0 後增加了一些新的機制,但並不是一種替代內建鎖的方
C++單例模式(執行緒安全、記憶體釋放)
一、懶漢模式:即第一次呼叫該類例項的時候才產生一個新的該類例項,並在以後僅返回此例項。 需要用鎖,來保證其執行緒安全性:原因:多個執行緒可能進入判斷是否已經存在例項的if語句,從而non thread safety. 使用double-check來保證thr
多執行緒中的佇列不一定需要執行緒安全
兩個執行緒,主執行緒中update update(){ while(queue.count >0){ //process.... queue.pop() } } 子執行緒中: queue.enqueue(data) 這樣做是沒有問
在 Java 的多執行緒中,如何去判斷給定的一個類是否是執行緒安全的(另外:synchronized 同步是否就一定能保證該類是執行緒安全的。)
同步程式碼塊和同步方法的區別:同步程式碼塊可以傳入任意物件,同步方法中 如果多個執行緒檢查的都是一個新的物件,不同的同步鎖對不同的執行緒不具有排他性,不能實現執行緒同步的效果,這時候執行緒同步就失效了。 兩者的區別主要體現在同步鎖上面。對於例項的同步方法,因為只能使用
關於hashmap和hashtable的區別,及如何使hashmap變得執行緒安全?(除了synchronized)---concurrentHashmap
我們都知道hashmap是執行緒不安全的,而效率也比較高,他允許我們存入null鍵及null值; 而 hashtable 是執行緒安全的,其效率比較低,不允許我們存入null鍵和null值; 除了非同步及允許使用null值,hashmap與hashtable基本相同; 那麼為什麼hash
String,StringBuffer與StringBuilder的區別|執行緒安全與執行緒不安全
轉載自https://www.cnblogs.com/xingzc/p/6277581.html侵權刪 String 字串常量 StringBuffer 字串變數(執行緒安全) StringBuilder 字串變數(非執行緒安全) 簡要的說, String 型別和 StringBuf