Java-Reentrantlock

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;

//條件:Condition 為Lock增加條件,當滿足條件時,做什麼事情,如枷鎖或解鎖。等待喚醒
public class TestContaniner<T> {
	private final LinkedList<T> list = new LinkedList<>();
	private final int MAX = 10;
	private int count = 0;

	private Lock lock = new ReentrantLock();
	private Condition product = lock.newCondition();
	private Condition consumer = lock.newCondition();

	public int getCount() {
		return count;
	}

	public void put(T t) {
		lock.lock();
		try {
			while (list.size() == MAX) {
				System.out.println(Thread.currentThread().getName() + "等待中。。。");
				// 進入等待隊列,釋放鎖標記
				// 藉助條件,進入的等待隊列
				product.await();
			}
			System.out.println(Thread.currentThread().getName() + "put...");
			list.add(t);
			count++;
			// 藉助條件,喚醒所有的消費者
			consumer.signalAll();
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	public T get() {
		T t = null;
		lock.lock();
		try {
			while (list.size() == 0) {
				System.out.println(Thread.currentThread().getName() + "等待...");
				consumer.await();
			}
			System.out.println(Thread.currentThread().getName() + "get...");
			t = list.removeFirst();
			count--;
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		} finally {
			lock.unlock();
		}
		return t;
	}

    public static void main(String[] args) {
		final TestContaniner<String> c=new TestContaniner<>();
		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();
		}
	}
}

  Java 虚拟机中的同步(Synchronization)基于进入和退出管程(Monitor)对象实现。同步方 法 并不是由 monitor enter 和 monitor exit 指令来实现同步的,而是由方法调用指令读取运 行时常量池中方法的 ACC_SYNCHRONIZED 标志来隐式实现的

 

 对象头:存储对象的 hashCode、锁信息或分代年龄或 GC 标志,类型指针指向对象的类 元数据,JVM 通过这个指针确定该对象是哪个类的实例等信息。 实例变量:存放类的属性数据信息,包括父类的属性信息 填充数据:由于虚拟机要求对象起始地址必须是 8 字节的整数倍。填充数据不是必须存 在的,仅仅是为了字节对齐 当在对象上加锁时,数据是记录在对象头中。当执行 synchronized 同步方法或同步代码 块时,会在对象头中记录锁标记,锁标记指向的是 monitor 对象(也称为管程或监视器锁) 的起始地址。每个对象都存在着一个 monitor 与之关联,对象与其 monitor 之间的关系有 存在多种实现方式,如 monitor 可以与对象一起创建销毁或当线程试图获取对象锁时自动生 成,但当一个 monitor 被某个线程持有后,它便处于锁定状态。 在 Java 虚拟机(HotSpot)中,monitor 是由 ObjectMonitor 实现的。 ObjectMonitor 中有两个队列,_WaitSet 和 _EntryList,以及_Owner 标记。其中_WaitSet 是用于管理等待队列(wait)线程的,_EntryList 是用于管理锁池阻塞线程的,_Owner 标记用于 记录当前执行线程。线程状态图如下: 

 

 当多线程并发访问 同一个同步代码 时,首先会进入_EntryList,当线程获取锁标记后, monitor 中的_Owner 记录此线程,并在 monitor 中的计数器执行递增计算(+1),代表锁定, 其他线程在_EntryList 中继续阻塞。若执行线程调用 wait 方法,则 monitor 中的计数器执行 赋值为 0 计算,并将_Owner 标记赋值为 null,代表放弃锁,执行线程进如_WaitSet 中阻塞。 若执行线程调用 notify/notifyAll 方法,_WaitSet 中的线程被唤醒,进入_EntryList 中阻塞,等 待获取锁标记。若执行线程的同步代码执行结束,同样会释放锁标记,monitor 中的_Owner 标记赋值为 null,且计数器赋值为 0 计算

posted @ 2019-11-05 19:29  石shi  阅读(128)  评论(0编辑  收藏  举报