• 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 计算

  • 相关阅读:
    ApacheServer-----关于443端口被占用的解决方法
    《小强与小明》——正在疯传的伟大的故事
    不争万年,只珍朝夕------我的态度
    dubbo搭建
    使用netty的第一个Hello World
    myBatis数据库常用标签
    mysql 索引
    tomcat部署项目的一点心得
    【康托展开】
    初探计算机硬盘
  • 原文地址:https://www.cnblogs.com/sunliyuan/p/11800969.html
Copyright © 2020-2023  润新知