使用synchronized來保證數據的同步

網上一搜索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是否存在,而且是否已完成。

而後會進行排隊,排隊以後,咱們會再次進行上述檢查。這兩次檢查,就是雙重功能檢查的意思。能夠避免出現多個線程重複執行某段代碼。假設沒有第二次檢查,則排隊線程得到鎖的時候,同樣會有「通知用戶」的行爲。

表達能力有限,不知道上述內容有沒有把我表達的意思說清楚。但願對看到本文的你有所幫助:-)。

相關文章
相關標籤/搜索