同步鎖使用的弊端:當線程任務中出現了多個同步(多個鎖)時,如果同步中嵌套了其他的同步。這時容易引發一種現象:程序出現無限等待,這種現象我們稱為死鎖。這種情況能避免就避免掉。
~~~
synchronzied(A鎖){
synchronized(B鎖){
}
}
~~~
這是一個關于死鎖的問題,代碼如下:

很明顯,這段代碼在多線程情況下,會產生死鎖:
假設線程1 做的操作是賬戶A給賬戶B轉賬, 先鎖住了A賬戶, 接下來試圖申請B賬戶的鎖,
與此同時線程2 在從 賬戶B給賬戶A 轉賬, 先鎖住了B賬戶的鎖, 接下來試圖申請A賬戶的鎖。
兩個線程各自持有資源, 然后等待獲取對方的資源, 都無法執行下去, 死鎖就出現了。
怎么寫代碼才能避免這種死鎖呢?下面的代碼是一種解決辦法:

這段代碼看起來有點吃力,但是如果你學過操作系統對死鎖的處理的話, 就變的很容易。
操作系統中的理論是這樣的: 如果有多個線程對多個資源進行訪問時, 需要對資源進行排序(排序的方法你自己確定), 然后所有的線程都按同樣的次序來訪問資源,這樣就不會出現環路等待了。
例如有10個線程, 每個都要訪問多個資源, 對資源排序以后, 大家都先鎖住1號資源進行訪問(注意同一時刻,只有一個線程能獲得鎖, 別的都得等待) 然后是2號, 3號。。。
由于大家訪問的次序是一樣的, 就不會出現死鎖的的情況。
理解了這一點, 對于上面的代碼就很容易理解了, 實際就是對Account(賬戶)進行資源的排序, 通過 Java 內置的方法,得到Hashcode。 然后按順序訪問。
如果fromAccount 比較小, 那就先鎖住fromAccount, 然后鎖住toAccount, 反過來也是類似。
假設線程1 做的操作是賬戶A給賬戶B轉賬, 先鎖住了A賬戶(假設A的hashcode 比較小), 接下來試圖申請B賬戶的鎖,
與此同時線程2 在從 賬戶B給賬戶A 轉賬, 由于A的hashcode 較小, 這個線程也試圖先申請A的鎖, 當然它申請不到, 因為已經被線程1持有了, 線程2只能等待
等到線程1完成操作以后, 線程2才能繼續, 死鎖就消除了。
如果兩個賬號的hashCode 相等怎么辦, 沒辦法,只好引用一個第三方的鎖了解決了, 這就是上述代碼的else 分支 synchronized(lock) .
- 基礎
- 編譯和安裝
- scanner類(鍵盤錄入)
- Random類(隨機數)
- 數組
- 方法
- 類
- ArrayList集合
- char與int
- eclipse
- IDEA
- 變量與常量
- 常用API
- String,StringBuffer,StringBuilder
- 正則,Date,DateFormat,Calendar
- 包裝類,System,Math,Arrays,BigInteger,BigDecimal
- 集合,迭代器,增強for,泛型
- List,set,判斷集合唯一
- map,Entry,HashMap,Collections
- 異常
- IO
- File
- 遞歸
- 字節流
- 字符流
- IO流分類
- 轉換流
- 緩沖流
- 流的操作規律
- properties
- 序列化流與反序列化流
- 打印流
- commons-IO
- IO流總結
- 多線程
- 線程池
- 線程安全
- 線程同步
- 死鎖
- lock接口
- ThreadLoad
- 等待喚醒機制
- 線程狀態
- jdbc
- DBUtils
- 連接池DBCP
- c3p0連接池
- 網絡編程
- 多線程socket上傳圖片
- 反射
- xml
- 設計模式
- 裝飾器模式
- web service
- tomcat
- Servlet
- response
- request
- session和cookie
- JSP
- EL
- JSTL
- 事務
- 監聽器Listener
- 過濾器Filter
- json
- linux安裝軟件
- 反射詳解
- 類加載器和注解
- 動態代理
- jedis
- Hibernate
- 簡介
- 創建映射文件
- Hibernate核心配置文件
- 事務和增刪改查
- HibernateUtils
- 持久化對象的三種狀態
- 檢索方式
- query
- Criteria
- SQLQuery
- 持久化類
- 主鍵生成策略
- 緩存
- 事務管理
- 關系映射
- 注解
- 優化
- struts2
- 搭建
- 配置詳解
- Action
- 結果跳轉方式
- 訪問ServletAPI方式
- 如何獲得參數
- OGNL表達式
- valueStack 值棧
- Interceptor攔截器
- spring
- 導包
- IOC和DI
- Bean獲取與實例化
- Bean屬性注入
- spring注解
- 注解分層
- junit整合
- aop
- 動態代理實現
- cglib代理實現
- aop名詞
- spring的aop
- aop-xml詳解
- aop-注解詳解
- 代理方式選擇
- jdbcTemplate
- spring事務管理
- 回滾注意
- 事務傳播屬性
- MyBatis
- MyBatis簡介
- 入門程序
- 與jdbc hibernate不同
- 原始Dao開發
- Mapper動態代理方式
- SqlMapConfig.xml配置文件
- 輸入參數pojo包裝類
- resultMap
- 動態sql
- 一對一關聯
- 一對多
- 整合spring
- 逆向工程
- maven
- maven簡介
- 倉庫
- maven目錄結構
- maven常用命令
- 生命周期
- eclipse中maven插件
- 入門程序
- 整合struct
- 依賴范圍
- 添加插件
- idea配置
- jar包沖突
- 分模塊開發
- 構建可執行的jar包(包含依賴jar包)
- springMVC
- 處理流程
- java面試
- java版本升級
- java1-8版本變更
- java9新特性
- 鎖
- java資料
- idea
- jdk版本切換
- log4j
- 入門實例
- 基本使用方法
- Web中使用Log4j
- spring中使用log4j
- java代碼優化