網上一搜索synchronized,資料大把大把,因此也不展開來講,怕說多錯多。簡單說說個人理解和用法。java
synchronized是Java中的關鍵字,是一種同步鎖。一般能夠用來修飾某個方法,或者某個代碼塊。線程
我通常用來修飾代碼塊,感受會更加靈活。先上個例子:code
public class Task implements Runnable{ private static final Object LOCK = new Object(); public void run(){ long threadId = Thread.currentThread().getId(); System.out.println(threadId + " 等待執行"); synchronized (LOCK) { try { System.out.println(threadId + " 執行中"); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(threadId + " 執行結束"); } } }
首先咱們定義了一個常量LOCK,執行到這個synchronized 代碼塊的時候,都會先檢查是否得到LOCK的使用權。對象
因爲LOCK是全局的常量,因此全部線程拿到的都是同一個LOCK對象,因此全部線程在到這裏的時候,都須要排隊等LOCK。get
即下面例子全部的調用,都會等待。PS.你也能夠去掉synchronized關鍵詞來看下另一種執行結果。同步
public static void main(String[] args) { ExecutorService service = Executors.newFixedThreadPool(10); for (int i=0; i<10; i++) { service.execute(new Task()); } }
若是LOCK的定義改成下面這種。io
private Object LOCK = new Object();
再執行上述的main方法,會發現,代碼塊裏面的內容再也不等待了。當一個線程執行時,另一個線程也開始執行了。class
爲何呢?由於每一個線程的LOCK再也不是同一個對象實例了。如今每一個LOCK都只屬於它們的類實例。thread
這時,咱們能夠這麼改。搜索
public static void main(String[] args) { ExecutorService service = Executors.newFixedThreadPool(10); Task task = new Task(); for (int i=0; i<10; i++) { service.execute(task); } }
對於每一個線程來講,LOCK都是同一個鎖,因此線程間會進行等待。
總結一句:synchronized修飾代碼塊的時候,可讓使用了同一個鎖對象實例的多個線程進行排隊等待執行。
再補充一個,使用synchronized的時候,常常要使用到雙重檢查。仍是直接舉例子吧。
假設咱們有個將任務修改成完成的功能,修改成完成狀態以後,還要通知發任務的用戶。若是不使用同步鎖進行控制,多人觸發同一個任務的完成操做時,可能會出現屢次通知同一個用戶的狀況。這時,咱們可使用synchronized來防止這個狀況。代碼大概是這樣的。
public void completeTask(long taskId) { Task task = Task.get(taskId); if(task!=null && task.hasCompleted()) { return; } synchronized (task) { task = Task.get(taskId); if(task!=null && task.hasCompleted()) { return; } Task.complete(task); NoticeUtil.noticeTaskComplete(task.getPublisher()); } }
一開始,咱們獲取了一個task實例,這裏,咱們必須保證對於相同taskId的task必須是同一個實例對象,synchronized纔會有效。
拿到task以後,咱們先檢查task是否存在,而且是否已完成。
而後會進行排隊,排隊以後,咱們會再次進行上述檢查。這兩次檢查,就是雙重功能檢查的意思。能夠避免出現多個線程重複執行某段代碼。假設沒有第二次檢查,則排隊線程得到鎖的時候,同樣會有「通知用戶」的行爲。
表達能力有限,不知道上述內容有沒有把我表達的意思說清楚。但願對看到本文的你有所幫助:-)。