java并发包中的Lock

1)Lock与synchronized的区别:java

1)Lock显示地获取和释放锁:
	void lock(); // 获取锁。
	void unlock(); // 释放锁。
	
2)能够非阻塞的获取锁:
	boolean tryLock(); // 调用该方法后马上返回,若是能获取到锁则返回true,不然返回false;
	
3)能够中断地获取锁:
	void lockInterruptibly() throws InterruptedException; // 在锁的获取过程当中,若是获取锁的线程被中断,则抛出中断异常并返回。
	
4)能够超时地获取锁:
	boolean tryLock(long time, TimeUnit unit) throws InterruptedException; // 在time时间内,获取到锁返回true,若是获取锁的线程被中断则返回false;超出time时间,返回false。

5)Condition newCondition();

	Condition:java.util.concurrent.locks.Condition
	
		1)每一个Condition对象都包含着一个等待队列,该队列是Condition对象实现等待/通知功能的关键。
		2)等待队列是一个FIFO的队列,在队列中的每一个节点都包含了一个线程引用,该线程就是在Condition对象上等待的线程。
		3)若是一个线程调用了Condition.await()方法,那么该线程将会释放锁,而且构形成节点加入等待队列并进入等待状态。
		4)事实上,同步队列(获取Lock排队)和等待队列(获取Condition排队)中节点的类型都是同步器的静态内部类AbstractQueuedSynchronizer.Node
		5)注意:在condition.await()方法调用以前,必须先用lock.lock()方法获取到锁。
		
6)多路通知功能:
	在一个Lock对象里面建立多个Condition实例,线程对象能够注册在指定的Condition中,从而能够有选择地进行线程通知。能够先对线程进行分组,而后再唤醒指定组中的线程。


实现:ReentrantLock、ReentrantReadWriteLock、CountDownLatch

2)ReentrantLock(重入锁):并发

重入:
	1)重入是指任意线程在获取到锁以后可以再次获取该锁而不会被阻塞。
	2)在调用lock()方法时,已经获取到锁的线程,可以再次调用lock()方法获取锁而不被阻塞。


重入的过程:
	1)线程再次获取锁:锁须要去识别获取锁的线程是否为当前占据锁的线程,若是是,则再次成功获取。
	2)锁的最终释放:
		1>获取锁时须要进行计数自增,计数表示当前锁被重复获取的次数,而锁被释放时,计数自减,当计数等于0时表示锁已经成功释放。
		2>线程重复n次获取了锁,随后在释放n次该锁后,其它线程可以获取到该锁。


支持获取锁时的公平性和非公平性选择:
	1)公平锁保证了锁的获取按照FIFO原则,其代价是须要进行大量的线程切换。
	2)非公平锁虽然可能形成线程“饥饿”,可是极少的线程切换,保证了其更大的吞吐量。


ReentrantLock类中封装的AQS的同步状态表示锁被一个线程重复获取的次数。


举例:
	------------------------------------------
	实现等待/通知的service类:
	import java.util.concurrent.locks.Condition;
	import java.util.concurrent.locks.Lock;
	import java.util.concurrent.locks.ReentrantLock;

	public class MessageService {
		
		private Lock lock = new ReentrantLock();
		public Condition conditionA = lock.newCondition();
		public Condition conditionB = lock.newCondition();
		
		public void awaitA() {
			try {
				lock.lock();
				System.out.println("start awaitA, time:" + System.currentTimeMillis() + " ThreadName:" + Thread.currentThread().getName());
				conditionA.await();
				System.out.println("end awaitA, time:" + System.currentTimeMillis() + " ThreadName:" + Thread.currentThread().getName());
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {
				lock.unlock();
			}
		}
		
		public void awaitB() {
			try {
				lock.lock();
				System.out.println("start awaitB, time:" + System.currentTimeMillis() + " ThreadName:" + Thread.currentThread().getName());
				conditionB.await();
				System.out.println("end awaitB, time:" + System.currentTimeMillis() + " ThreadName:" + Thread.currentThread().getName());
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {
				lock.unlock();
			}
		}
		
		public void signalAllforA() {
			try {
				lock.lock();
				System.out.println("signalAllforA, time:" + System.currentTimeMillis() + " ThreadName:" + Thread.currentThread().getName());
				conditionA.signalAll();
			} finally {
				lock.unlock();
			}
		}
		
		public void signalAllforB() {
			try {
				lock.lock();
				System.out.println("signalAllforB, time:" + System.currentTimeMillis() + " ThreadName:" + Thread.currentThread().getName());
				conditionB.signalAll();
			} finally {
				lock.unlock();
			}
		}
	}
	---------------------
	线程A
	public class ThreadA extends Thread{

		private MessageService messageService;
		
		public ThreadA(MessageService messageService) {
			this.messageService = messageService;
		}
		
		[@Override](https://my.oschina.net/u/1162528)
		public void run() {
			this.messageService.awaitA();
		}
	}
	---------------------
	线程B
	public class ThreadB extends Thread{

		private MessageService messageService;
		
		public ThreadB(MessageService messageService) {
			this.messageService = messageService;
		}
		
		[@Override](https://my.oschina.net/u/1162528)
		public void run() {
			this.messageService.awaitB();
		}
	}

	---------------------
	测试类:
		public class LockTest {

			public static void main(String[] args) {
				try {
					MessageService messageService = new MessageService();
					ThreadA threadA = new ThreadA(messageService);
					threadA.setName("Thread-A");
					threadA.start();
					ThreadB threadB = new ThreadB(messageService);
					threadB.setName("Thread-B");
					threadB.start();
					
					Thread.sleep(5000);
					messageService.signalAllforA(); // 运行后,只有ThreadA被唤醒了
					
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}

		结果:
			start awaitA, time:1497603307947 ThreadName:Thread-A
			start awaitB, time:1497603307947 ThreadName:Thread-B
			signalAllforA, time:1497603312947 ThreadName:main
			end awaitA, time:1497603312947 ThreadName:Thread-A

	------------------------------------------

3)ReadWriteLock(读写锁):ide

概念:读写锁维护了一对锁,一个读锁和一个写锁,经过分离读锁和写锁,使得并发性相比通常的独占锁有了很大提高。


源码:

	package java.util.concurrent.locks;
		
	public interface ReadWriteLock {
	
		/** Returns the lock used for reading. */
		Lock readLock();

		/** Returns the lock used for writing. */
		Lock writeLock();
	}


说明:
	1)读写锁在同一时刻能够容许多个读线程访问,可是在写线程访问时,其它的读线程和写线程均被阻塞。
	2)若是当前线程获取了写锁或者写锁未被获取,则当前线程能够获取读锁。
	3)若是当前线程在获取读锁时,写锁已被其余线程获取,则进入等待状态。
	4)通常状况下,读写锁的性能都会比独占锁好,由于大多数场景读是多于写的。
	5)在读多于写的状况下,读写锁可以提供比独占锁更好的并发性和吞吐量。


实现:ReentrantReadWriteLock

	特色:
		1)支持公平性选择
		2)支持读锁和写锁的重入
		3)支持锁降级:
			1>锁降级的概念:先获取到写锁后,再获取到读锁,随后才释放写锁,最后只持有读锁的过程。
			2>按照获取写锁、获取读锁、释放写锁的顺序进行操做,从而将写锁降级为读锁。
			
	说明:
		1)若是存在读锁,则写锁不能被获取,进入等待状态。
		2)若是其它线程已经获取了写锁,则当前线程不能获取读锁,进入等待状态。

		
读写状态的设计:

	在一个整型变量上维护多种状态,就须要“按位切割使用”这个变量,读写锁将变量切分红了两个部分,高16位表示读,低16位表示写。
相关文章
相关标签/搜索