1. 程式人生 > >Synchronized不一定是執行緒安全的吧?_wait釋放同步鎖

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