多執行緒(二)

Kakarotto發表於2018-04-27

一、ReentrantLock

1、重入鎖

/**
 * ReentrantLock
 *  重入鎖
 */
package concurrent.t03;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test_01 {
	Lock lock = new ReentrantLock();
	
	void m1(){
		try{
			lock.lock(); // 加鎖
			for(int i = 0; i < 10; i++){
				TimeUnit.SECONDS.sleep(1);
				System.out.println("m1() method " + i);
			}
		}catch(InterruptedException e){
			e.printStackTrace();
		}finally{
			lock.unlock(); // 解鎖
		}
	}
	
	void m2(){
		lock.lock();
		System.out.println("m2() method");
		lock.unlock();
	}
	
	public static void main(String[] args) {
		final Test_01 t = new Test_01();
		new Thread(new Runnable() {
			@Override
			public void run() {
				t.m1();
			}
		}).start();
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		new Thread(new Runnable() {
			@Override
			public void run() {
				t.m2();
			}
		}).start();
	}
}
複製程式碼

結果:

m1() method 0
m1() method 1
m1() method 2
m1() method 3
m1() method 4
m1() method 5
m1() method 6
m1() method 7
m1() method 8
m1() method 9
m2() method
複製程式碼

2、嘗試鎖

/**
 * 嘗試鎖
 */
package concurrent.t03;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test_02 {
	Lock lock = new ReentrantLock();
	
	void m1(){
		try{
			lock.lock();
			for(int i = 0; i < 10; i++){
				TimeUnit.SECONDS.sleep(1);
				System.out.println("m1() method " + i);
			}
		}catch(InterruptedException e){
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
	}
	
	void m2(){
		boolean isLocked = false;
		try{
			// 嘗試鎖, 如果有鎖,無法獲取鎖標記,返回false。
			// 如果獲取鎖標記,返回true
			// isLocked = lock.tryLock();
			
			// 阻塞嘗試鎖,阻塞引數代表的時長,嘗試獲取鎖標記。
			// 如果超時,不等待。直接返回。
			isLocked = lock.tryLock(5, TimeUnit.SECONDS); 
			
			if(isLocked){
				System.out.println("m2() method synchronized");
			}else{
				System.out.println("m2() method unsynchronized");
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			if(isLocked){
				// 嘗試鎖在解除鎖標記的時候,一定要判斷是否獲取到鎖標記。
				// 如果當前執行緒沒有獲取到鎖標記,會丟擲異常。
				lock.unlock();
			}
		}
	}
	
	public static void main(String[] args) {
		final Test_02 t = new Test_02();
		new Thread(new Runnable() {
			@Override
			public void run() {
				t.m1();
			}
		}).start();
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		new Thread(new Runnable() {
			@Override
			public void run() {
				t.m2();
			}
		}).start();
	}
}
複製程式碼

結果:

m1() method 0
m1() method 1
m1() method 2
m1() method 3
m1() method 4
m1() method 5
m2() method unsynchronized
m1() method 6
m1() method 7
m1() method 8
m1() method 9
複製程式碼

3、嘗試打斷(lockInterruptibly )

/**
 * 可打斷
 * 
 * 阻塞狀態: 包括普通阻塞,等待佇列,鎖池佇列。
 * 普通阻塞: sleep(10000), 可以被打斷。呼叫thread.interrupt()方法,可以打斷阻塞狀態,丟擲異常。
 * 等待佇列: wait()方法被呼叫,也是一種阻塞狀態,只能由notify喚醒。無法打斷
 * 鎖池佇列: 無法獲取鎖標記。不是所有的鎖池佇列都可被打斷。
 *  使用ReentrantLock的lock方法,獲取鎖標記的時候,如果需要阻塞等待鎖標記,無法被打斷。
 *  使用ReentrantLock的lockInterruptibly方法,獲取鎖標記的時候,如果需要阻塞等待,可以被打斷。
 * 
 */
package concurrent.t03;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test_03 {
	Lock lock = new ReentrantLock();
	
	void m1(){
		try{
			lock.lock();
			for(int i = 0; i < 5; i++){
				TimeUnit.SECONDS.sleep(1);
				System.out.println("m1() method " + i);
			}
		}catch(InterruptedException e){
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
	}
	
	void m2(){
		try{
			lock.lockInterruptibly(); // 可嘗試打斷,阻塞等待鎖。可以被其他的執行緒打斷阻塞狀態
			System.out.println("m2() method");
		}catch(InterruptedException e){
			System.out.println("m2() method interrupted");
		}finally{
			try{
				lock.unlock();
			}catch(Exception e){
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
		final Test_03 t = new Test_03();
		new Thread(new Runnable() {
			@Override
			public void run() {
				t.m1();
			}
		}).start();
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				t.m2();
			}
		});
		t2.start();
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		t2.interrupt();// 打斷執行緒休眠。非正常結束阻塞狀態的執行緒,都會丟擲異常。
	}
}
複製程式碼

結果:

m1() method 0
m1() method 1
m2() method interrupted
java.lang.IllegalMonitorStateException
	at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(Unknown Source)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(Unknown Source)
	at java.util.concurrent.locks.ReentrantLock.unlock(Unknown Source)
	at concurrent.t03.Test_03.m2(Test_03.java:43)
	at concurrent.t03.Test_03$2.run(Test_03.java:67)
	at java.lang.Thread.run(Unknown Source)
m1() method 2
m1() method 3
m1() method 4
複製程式碼

4、公平鎖

/**
 * 公平鎖
 */
package concurrent.t03;

import java.util.concurrent.locks.ReentrantLock;

public class Test_04 {
	
	public static void main(String[] args) {
		TestReentrantlock t = new TestReentrantlock();
		//TestSync t = new TestSync();
		Thread t1 = new Thread(t);
		Thread t2 = new Thread(t);
		t1.start();
		t2.start();
	}
}

class TestReentrantlock extends Thread{
	// 定義一個公平鎖
	private static ReentrantLock lock = new ReentrantLock(true);
	public void run(){
		for(int i = 0; i < 5; i++){
			lock.lock();
			try{
				System.out.println(Thread.currentThread().getName() + " get lock");
			}finally{
				lock.unlock();
			}
		}
	}
	
}

class TestSync extends Thread{
	public void run(){
		for(int i = 0; i < 5; i++){
			synchronized (this) {
				System.out.println(Thread.currentThread().getName() + " get lock in TestSync");
			}
		}
	}
}
複製程式碼

結果:

Thread-2 get lock
Thread-1 get lock
Thread-2 get lock
Thread-1 get lock
Thread-2 get lock
Thread-1 get lock
Thread-2 get lock
Thread-1 get lock
Thread-2 get lock
Thread-1 get lock
複製程式碼

二、生產者消費者

1)、wait&notify

/**
 * 生產者消費者
 * wait&notify
 * wait/notify都是和while配合應用的。可以避免多執行緒併發判斷邏輯失效問題。
 */
package concurrent.t04;

import java.util.LinkedList;
import java.util.concurrent.TimeUnit;

public class TestContainer01<E> {

	private final LinkedList<E> list = new LinkedList<>();
	private final int MAX = 10;
	private int count = 0;
	
	public synchronized int getCount(){
		return count;
	}
	
	public synchronized void put(E e){
		while(list.size() == MAX){
			try {
				this.wait();
			} catch (InterruptedException e1) {
				e1.printStackTrace();
			}
		}
		
		list.add(e);
		count++;
		this.notifyAll();
	}
	
	public synchronized E get(){
		E e = null;
		while(list.size() == 0){
			try{
				this.wait();
			} catch (InterruptedException e1) {
				e1.printStackTrace();
			}
		}
		e = list.removeFirst();
		count--;
		this.notifyAll();
		return e;
	}
	
	public static void main(String[] args) {
		final TestContainer01<String> c = new TestContainer01<>();
		for(int i = 0; i < 10; i++){
			new Thread(new Runnable() {
				@Override
				public void run() {
					for(int j = 0; j < 5; j++){
						System.out.println(c.get());
					}
				}
			}, "consumer"+i).start();
		}
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		for(int i = 0; i < 2; i++){
			new Thread(new Runnable() {
				@Override
				public void run() {
					for(int j = 0; j < 25; j++){
						c.put("container value " + j); 
					}
				}
			}, "producer"+i).start();
		}
	}
	
}
複製程式碼

結果:

container value 0
container value 5
container value 6
container value 5
container value 6
container value 4
container value 1
container value 3
container value 2
container value 1
container value 0
container value 4
container value 2
container value 3
複製程式碼

2)、重入鎖&條件

/**
 * 生產者消費者
 * 重入鎖&條件
 * 條件 - Condition, 為Lock增加條件。當條件滿足時,做什麼事情,如加鎖或解鎖。如等待或喚醒
 */
package concurrent.t04;

import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TestContainer02<E> {

	private final LinkedList<E> list = new LinkedList<>();
	private final int MAX = 10;
	private int count = 0;
	
	private Lock lock = new ReentrantLock();
	private Condition producer = lock.newCondition();
	private Condition consumer = lock.newCondition();
	
	public int getCount(){
		return count;
	}
	
	public void put(E e){
		lock.lock();
		try {
			while(list.size() == MAX){
				System.out.println(Thread.currentThread().getName() + " 等待。。。");
				// 進入等待佇列。釋放鎖標記。
				// 藉助條件,進入的等待佇列。
				producer.await();
			}
			System.out.println(Thread.currentThread().getName() + " put 。。。");
			list.add(e);
			count++;
			// 藉助條件,喚醒所有的消費者。
			consumer.signalAll();
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		} finally {
			lock.unlock();
		}
	}
	
	public E get(){
		E e = null;

		lock.lock();
		try {
			while(list.size() == 0){
				System.out.println(Thread.currentThread().getName() + " 等待。。。");
				// 藉助條件,消費者進入等待佇列
				consumer.await();
			}
			System.out.println(Thread.currentThread().getName() + " get 。。。");
			e = list.removeFirst();
			count--;
			// 藉助條件,喚醒所有的生產者
			producer.signalAll();
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		} finally {
			lock.unlock();
		}
		
		return e;
	}
	
	public static void main(String[] args) {
		final TestContainer02<String> c = new TestContainer02<>();
		for(int i = 0; i < 10; i++){
			new Thread(new Runnable() {
				@Override
				public void run() {
					for(int j = 0; j < 5; j++){
						System.out.println(c.get());
					}
				}
			}, "consumer"+i).start();
		}
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}
		for(int i = 0; i < 2; i++){
			new Thread(new Runnable() {
				@Override
				public void run() {
					for(int j = 0; j < 25; j++){
						c.put("container value " + j); 
					}
				}
			}, "producer"+i).start();
		}
	}
	
}
複製程式碼

結果:

consumer0 等待。。。
consumer1 等待。。。
consumer2 等待。。。
consumer3 等待。。。
consumer6 等待。。。
consumer5 等待。。。
consumer9 等待。。。
consumer8 等待。。。
consumer4 等待。。。
consumer7 等待。。。
producer0 put 。。。
producer0 put 。。。
producer0 put 。。。
producer0 put 。。。
producer0 put 。。。
producer0 put 。。。
producer0 put 。。。
producer0 put 。。。
producer0 put 。。。
producer0 put 。。。
producer0 等待。。。
producer1 等待。。。
consumer0 get 。。。
container value 0
consumer0 get 。。。
container value 1
consumer0 get 。。。
container value 2
consumer0 get 。。。
container value 3
consumer1 get 。。。
container value 4
consumer1 get 。。。
container value 5
consumer2 get 。。。
container value 6
consumer3 get 。。。
container value 7
consumer3 get 。。。
container value 8
consumer6 get 。。。
container value 9
consumer6 等待。。。
consumer5 等待。。。
consumer9 等待。。。
consumer8 等待。。。
consumer4 等待。。。
consumer7 等待。。。
producer0 put 。。。
producer0 put 。。。
producer1 put 。。。
producer1 put 。。。
consumer0 get 。。。
container value 10
consumer1 get 。。。
container value 11
consumer1 get 。。。
container value 0
consumer1 get 。。。
container value 1
consumer2 等待。。。
consumer3 等待。。。
consumer6 等待。。。
consumer5 等待。。。
consumer9 等待。。。
consumer8 等待。。。
consumer4 等待。。。
consumer7 等待。。。
producer0 put 。。。
producer0 put 。。。
producer0 put 。。。
producer0 put 。。。
producer0 put 。。。
producer0 put 。。。
producer0 put 。。。
producer0 put 。。。
producer0 put 。。。
producer0 put 。。。
producer0 等待。。。
producer1 等待。。。
consumer2 get 。。。
container value 12
consumer2 get 。。。
container value 13
consumer2 get 。。。
container value 14
consumer2 get 。。。
container value 15
consumer3 get 。。。
container value 16
consumer6 get 。。。
container value 17
consumer6 get 。。。
container value 18
consumer5 get 。。。
container value 19
consumer9 get 。。。
container value 20
consumer9 get 。。。
container value 21
consumer8 等待。。。
consumer4 等待。。。
consumer7 等待。。。
producer0 put 。。。
producer0 put 。。。
producer1 put 。。。
producer1 put 。。。
producer1 put 。。。
producer1 put 。。。
producer1 put 。。。
producer1 put 。。。
producer1 put 。。。
producer1 put 。。。
producer1 等待。。。
consumer3 get 。。。
container value 22
consumer6 get 。。。
container value 23
consumer5 get 。。。
container value 2
consumer5 get 。。。
container value 3
consumer5 get 。。。
container value 4
consumer5 get 。。。
container value 5
consumer9 get 。。。
container value 6
consumer8 get 。。。
container value 7
consumer4 get 。。。
container value 8
consumer4 get 。。。
container value 9
consumer7 等待。。。
producer0 put 。。。
producer1 put 。。。
producer1 put 。。。
producer1 put 。。。
producer1 put 。。。
producer1 put 。。。
producer1 put 。。。
producer1 put 。。。
producer1 put 。。。
producer1 put 。。。
producer1 等待。。。
consumer3 get 。。。
container value 24
consumer6 get 。。。
container value 10
consumer9 get 。。。
container value 11
consumer8 get 。。。
container value 12
consumer8 get 。。。
container value 13
consumer8 get 。。。
container value 14
consumer8 get 。。。
container value 15
consumer4 get 。。。
container value 16
consumer7 get 。。。
container value 17
producer1 put 。。。
producer1 put 。。。
producer1 put 。。。
producer1 put 。。。
producer1 put 。。。
producer1 put 。。。
consumer9 get 。。。
container value 18
consumer4 get 。。。
container value 19
consumer7 get 。。。
container value 20
consumer7 get 。。。
container value 21
consumer7 get 。。。
container value 22
consumer7 get 。。。
container value 23
consumer4 get 。。。
container value 24
複製程式碼

相關文章