012 內置鎖和synchronized
一 . 概述
在前面我們說到線程安全性問題解決的核心就是同步,同步的核心就是保證原子性.
在java之中最早就支持語法層面的同步解決了,並且提供了synchronized的方式解決問題.
二 .內置鎖
在java之中每一個對象都是一個內置鎖,這個在JVM的體系之中就規定好了.
內置鎖的規定也就決定我們可以拿任意的對象進行同步操作.
內置鎖常常配合synchronized使用.
三 .synchronized
該關鍵詞的作用是同步,需要配合內置鎖進行使用.
常見的synchronized的使用方式有三種:
[1]在靜態方法中使用
[2]在實例方法中使用
[3]在同步代碼塊之中使用
其中: 在靜態方法之中的內置鎖是該類的class對象,實例方法的內置鎖是調用該方法的實例對象.
在同步代碼塊之中的內置鎖需要顯示的指定.
四 . 例子
將我們之前的計數代碼進行改寫,變成線程安全的操作.
public class ProblemSolve { private int count = 0; public static void main(String[] args) throws Exception { ProblemSolve demo = new ProblemSolve(); Thread t1= new Thread(new Runnable() { @Override public void run() { for(int x =0;x<10000;x++) { demo.add(); } } }); Thread t2 = new Thread(new Runnable() { @Override publicvoid run() { for(int x =0;x<10000;x++) { demo.add(); } } }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println("獲取最終的結果count : " + demo.count); } private synchronized void add() { count++; } }
我們所作出的概念僅僅是加上了一個synchronized關鍵詞就完成了同步的操作,這樣我們就能保證線程安全性.
五 .分析
當我們的代碼進入同步代碼的時候,會試圖獲取內置鎖.
獲取成功: 繼續運行
獲取失敗: 進入該內置所的阻塞隊列.直到獲取該所的線程完成任務或者自己釋放內置所的擁有權.
然後阻塞隊列的線程重新進入runnable狀態,再此嘗試獲取該鎖.
以上就是synchronized同步的底層運行方式.
六. synchronized的優劣
優勢 : 保證原子性,因為同步的代碼僅僅只有一個線程可以運行.
劣勢: 粒度過大,獲取不到內置鎖的線程會進入阻塞隊列等待喚醒,這個是一刀切的方式,很有可能會影響性能.
解決: 在jak6之後,對synchronized關鍵詞的實現進行了優化,這個在下面會介紹.
012 內置鎖和synchronized