Synchronization in Java with Examples - Java 147

Synchronization in Java with Examples – Java 147

Synchronization in Java with Examples

同步是控制多個執行緒訪問任何共享資源的能力,如果希望只允許一個執行緒訪問共享資源,使用 Synchronized 是其中的一個選擇,使用方法是需要指定一個物件,當程式進入 Synchronized 區塊或方法時,該物件會被鎖定,直到離開 Synchronized 區塊或方法時才會被釋放, Synchronization in Java 本篇增加了範例,並透過單元測試來驗證產出結果。

檔案目錄

./
   +- src
       +- test
       |   +- org
       |       +- ruoxue
       |           +- java_147
       |               +- synchronization
       |                   +- SynchronizationWithExamplesTest.java  

單元測試

Synchronization Java 提供同步等操作。

noSync

建立 3 個執行緒,不加 synchronized ,對計數器加 1 ,然後結束任務,最終結果會不如預期。

	protected class NoSyncCounter {

		private int count;

		public NoSyncCounter() {
		}

		public void increment() {
			count = getCount() + 1;
			System.out.println(String.format("T[%d] count: %d", Thread.currentThread().getId(), count));
		}

		public int getCount() {
			return count;
		}
	}

	@Test
	public void noSync() {
		int expected = 1000;
		int taskSize = 1000;
		ExecutorService executorService = Executors.newFixedThreadPool(3);
		NoSyncCounter counter = new NoSyncCounter();
		IntStream.range(0, taskSize).forEach(e -> {
			executorService.submit(counter::increment);
		});

		executorService.shutdown();
		try {
			if (!executorService.awaitTermination(3, TimeUnit.SECONDS)) {
				executorService.shutdownNow();
			}
		} catch (InterruptedException e) {
			executorService.shutdownNow();
		}
		int count = counter.getCount();
		System.out.println(count);
		assertEquals(expected, count);
	}
T[12] count: 997
T[12] count: 998
T[12] count: 999
T[13] count: 989
T[11] count: 933
999

syncMethod

Synchronization Java 建立 3 個執行緒,在方法上加 synchronized ,對計數器加 1 ,然後結束任務。

	protected class SyncMethodCounter {

		private int count;

		public SyncMethodCounter() {
		}

		public synchronized void increment() {
			count = getCount() + 1;
			System.out.println(String.format("T[%d] count: %d", Thread.currentThread().getId(), count));
		}

		public int getCount() {
			return count;
		}
	}

	@Test
	public void syncMethod() {
		int expected = 1000;
		int taskSize = 1000;
		ExecutorService executorService = Executors.newFixedThreadPool(3);
		SyncMethodCounter counter = new SyncMethodCounter();
		IntStream.range(0, taskSize).forEach(e -> {
			executorService.submit(counter::increment);
		});

		executorService.shutdown();
		try {
			if (!executorService.awaitTermination(3, TimeUnit.SECONDS)) {
				executorService.shutdownNow();
			}
		} catch (InterruptedException e) {
			executorService.shutdownNow();
		}
		int count = counter.getCount();
		System.out.println(count);
		assertEquals(expected, count);
	}
T[12] count: 996
T[12] count: 997
T[12] count: 998
T[13] count: 999
T[11] count: 1000
1000

syncBlock

Synchronization Java 建立 3 個執行緒,在區塊上加 synchronized ,對計數器加 1 ,然後結束任務。

	protected class SyncBlockCounter {

		private int count;

		public SyncBlockCounter() {
		}

		public void increment() {
			synchronized (this) {
				count = getCount() + 1;
				System.out.println(String.format("T[%d] count: %d", Thread.currentThread().getId(), count));
			}
		}

		public int getCount() {
			return count;
		}
	}

	@Test
	public void syncBlock() {
		int expected = 1000;
		int taskSize = 1000;
		ExecutorService executorService = Executors.newFixedThreadPool(3);
		SyncBlockCounter counter = new SyncBlockCounter();
		IntStream.range(0, taskSize).forEach(e -> {
			executorService.submit(counter::increment);
		});

		executorService.shutdown();
		try {
			if (!executorService.awaitTermination(3, TimeUnit.SECONDS)) {
				executorService.shutdownNow();
			}
		} catch (InterruptedException e) {
			executorService.shutdownNow();
		}
		int count = counter.getCount();
		System.out.println(count);
		assertEquals(expected, count);
	}
T[11] count: 996
T[11] count: 997
T[11] count: 998
T[13] count: 999
T[12] count: 1000
1000

SynchronizationWithExamplesTest.java

Java Synchronization 新增單元測試,驗證是否符合預期。

package org.ruoxue.java_147.synchronization;

import static org.junit.Assert.assertEquals;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

import org.junit.Test;

public class SynchronizationWithExamplesTest {

	protected class NoSyncCounter {

		private int count;

		public NoSyncCounter() {
		}

		public void increment() {
			count = getCount() + 1;
			System.out.println(String.format("T[%d] count: %d", Thread.currentThread().getId(), count));
		}

		public int getCount() {
			return count;
		}
	}

	@Test
	public void noSync() {
		int expected = 1000;
		int taskSize = 1000;
		ExecutorService executorService = Executors.newFixedThreadPool(3);
		NoSyncCounter counter = new NoSyncCounter();
		IntStream.range(0, taskSize).forEach(e -> {
			executorService.submit(counter::increment);
		});

		executorService.shutdown();
		try {
			if (!executorService.awaitTermination(3, TimeUnit.SECONDS)) {
				executorService.shutdownNow();
			}
		} catch (InterruptedException e) {
			executorService.shutdownNow();
		}
		int count = counter.getCount();
		System.out.println(count);
		assertEquals(expected, count);
	}

	protected class SyncMethodCounter {

		private int count;

		public SyncMethodCounter() {
		}

		public synchronized void increment() {
			count = getCount() + 1;
			System.out.println(String.format("T[%d] count: %d", Thread.currentThread().getId(), count));
		}

		public int getCount() {
			return count;
		}
	}

	@Test
	public void syncMethod() {
		int expected = 1000;
		int taskSize = 1000;
		ExecutorService executorService = Executors.newFixedThreadPool(3);
		SyncMethodCounter counter = new SyncMethodCounter();
		IntStream.range(0, taskSize).forEach(e -> {
			executorService.submit(counter::increment);
		});

		executorService.shutdown();
		try {
			if (!executorService.awaitTermination(3, TimeUnit.SECONDS)) {
				executorService.shutdownNow();
			}
		} catch (InterruptedException e) {
			executorService.shutdownNow();
		}
		int count = counter.getCount();
		System.out.println(count);
		assertEquals(expected, count);
	}

	protected class SyncBlockCounter {

		private int count;

		public SyncBlockCounter() {
		}

		public void increment() {
			synchronized (this) {
				count = getCount() + 1;
				System.out.println(String.format("T[%d] count: %d", Thread.currentThread().getId(), count));
			}
		}

		public int getCount() {
			return count;
		}
	}

	@Test
	public void syncBlock() {
		int expected = 1000;
		int taskSize = 1000;
		ExecutorService executorService = Executors.newFixedThreadPool(3);
		SyncBlockCounter counter = new SyncBlockCounter();
		IntStream.range(0, taskSize).forEach(e -> {
			executorService.submit(counter::increment);
		});

		executorService.shutdown();
		try {
			if (!executorService.awaitTermination(3, TimeUnit.SECONDS)) {
				executorService.shutdownNow();
			}
		} catch (InterruptedException e) {
			executorService.shutdownNow();
		}
		int count = counter.getCount();
		System.out.println(count);
		assertEquals(expected, count);
	}
}

心得分享

Synchronization Thread in Java 訪問共享資源時提供方法同步,操作共享資源的程式碼被 Synchronized 所包圍,這會鎖定當前工作執行緒,並阻止所有其他試圖鎖定共享資源的執行緒,待 Synchronized 區塊執行完釋放鎖後,鎖定同一物件的其他執行緒,才有機會進行鎖定, Java Synchronization 提供了幾種 Synchronized 常見方法的操作範例。。

發佈留言