java并发编程总结二ReentrantLock

1. ReentrantLock概述

可重入性描述这样的一个问题:一个线程在持有一个锁的时候,它内部能否再次(多次)申请该锁。如果一个线程已经获得了锁,其内部还可以多次申请该锁成功。

void methodA(){
    lock.lock(); // 获取锁
    methodB();
    lock.unlock() // 释放锁
}

void methodB(){
    lock.lock(); // 获取锁
    // 其他业务
    lock.unlock();// 释放锁
}

2. Lock接口,ReentrantLock说明

Modifier and TypeMethodDescription
voidlock()获取锁
voidlockInterruptibly()除非当前线程被中断,否则获取锁定
ConditionnewCondition()返回绑定到此Lock实例的新Condition实例
booleantryLock()只有在调用时它是空闲的才能获取锁
booleantryLock(long time, TimeUnit unit)如果在给定的等待时间内空闲并且当前线程未被中断,则获取锁
voidunlock()释放锁
2.1 lock 和unlock方法说明

下面的事例模拟售票的场景, tickets是总票数,开启了10个售票窗口,售完为止:

public class ReentrantLockDemo01 implements Runnable {

    private Lock lock = new ReentrantLock();

    private int tickets = 200;

    @Override
    public void run() {
        while (true) {
            lock.lock(); // 获取锁
            try {
                if (tickets > 0) {
                    TimeUnit.MILLISECONDS.sleep(100);
                    System.out.println(Thread.currentThread().getName() + " " + tickets--);
                } else {
                    break;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock(); // 释放所
            }
        }
    }

    public static void main(String[] args) {
        ReentrantLockDemo01 reentrantLockDemo = new ReentrantLockDemo01();
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(reentrantLockDemo, "thread" + i);
            thread.start();
        }
    }
}
2.2 LockInterruptibly 方法
  • 使用ReentrantLock还可以调用lockInterruptibly方法,可以对线程interrupt方法做出响应
  • 在一个线程等到的过程中,可以被打断
public class ReentrantLock3 {
	Lock lock = new ReentrantLock();
	
	public static void main(String[] args) {
		Lock lock = new ReentrantLock();
		
		Thread t1 = new Thread(() -> {
			try {
				lock.lock();
				System.out.println("t1 start........");
				TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
				System.out.println("t1 end..........");
			} catch (InterruptedException e) {
				// TODO: handle exception
				System.out.println("interrupted......");
			} finally {
				lock.unlock();
			}
		});
		t1.start();
		
		
		Thread t2 = new Thread(() -> {
			try {
//				lock.lock();
				lock.lockInterruptibly(); //可以对interrupted方法做出响应
				System.out.println("t2 start........");
				
				TimeUnit.SECONDS.sleep(5);
				
				System.out.println("t2  end...........");
			} catch (Exception e) {
				// TODO: handle exception
				System.out.println("interrupted.......");
			} finally {
				if(lock.tryLock()) {
					lock.unlock();
					System.out.println("unlock....");
				}
//				lock.unlock();//,t2的finally代码块中的lock.unlock()会报异常,原因在于lock根本没有上锁
			}
		});
		
		t2.start();
		
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		t2.interrupt();//打断线程2 的等待,但是t1仍会继续执行
		
	}
}
2.3 tryLock 方法
  • 使用tryLock来尝试上锁,上锁成功则返回true,否则返回false
public class ReentrantLock4 {
	Lock lock = new ReentrantLock();
	
	void m1() {
		try {
			lock.lock();
			for (int i = 0; i < 10; i++) {

				TimeUnit.SECONDS.sleep(1);
				
				System.out.println(i);
			}
		} catch (InterruptedException e) {
				e.printStackTrace();
		} finally {
				lock.unlock();
		}
		
	}
	

	
	void m2() {
		
//		boolean locked = lock.tryLock();
//		System.out.println("m2......." + locked);
//		if(locked) lock.unlock();
		
		boolean locked = false;
		try {
			locked = lock.tryLock(5, TimeUnit.SECONDS);
			System.out.println("m2......." + locked);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally {
			if(locked)
				lock.unlock();
		}
	}
	
	public static void main(String[] args) {
		ReentrantLock4 r1 = new ReentrantLock4();
		
		new Thread(r1::m1).start();
		
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		
		new Thread(r1::m2).start();
	}
}
2.4 锁的手动释放
  • 需要注意的是,使用reentrantLock必须手工释放锁
  • 使用synchronized锁如果出现异常的话,jvm会自动释放锁,但是lock必须手工释放,可以在finally代码块中释放
public class ReentrantLock2 {
	Lock lock = new ReentrantLock();
	
	void m1() {
		try {
			lock.lock();
			for (int i = 0; i < 10; i++) {

				TimeUnit.SECONDS.sleep(1);
				
				System.out.println(i);
			}
		} catch (InterruptedException e) {
				e.printStackTrace();
		}finally {
				lock.unlock();
		}
		
	}
	
	void m2() {
		lock.lock();
		System.out.println("m2............");
		lock.unlock();
	}
	
	public static void main(String[] args) {
		ReentrantLock2 r1 = new ReentrantLock2();
		
		new Thread(r1::m1).start();
		
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		
		new Thread(r1::m2).start();
	}
}
2.5 公平锁
  • ReentrantLock可以指定为公平锁,默认的synchronized是非公平锁
  • 公平锁是谁等的时间长,锁给谁
public class ReentrantLock5 extends Thread{
	private static ReentrantLock lock = new ReentrantLock(true);//参数为true表明其为公平锁
	
	public void run() {
		for (int i = 0; i < 100; i++) {
			lock.lock();
			try {
				System.out.println(Thread.currentThread().getName() + "get the lock");
			} finally {
				lock.unlock();
			}
		}
	}
	
	public static void main(String[] args) {
		ReentrantLock5 r1 = new ReentrantLock5();
		
		Thread t1 = new Thread(r1);
		Thread t2 = new Thread(r1);
		
		t1.start();
		t2.start();
		
		
	}
}
2.6 newCondition() 方法说明
  • Condition的作用是对锁进行更精确的控制
  • Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalAll()相当于Object的notifyAll()方法。
  • 不同的是,Object中的wait(),notify(),notifyAll()方法是和”同步锁”(synchronized关键字)捆绑使用的;而Condition是需要与”互斥锁”/”共享锁”捆绑使用的。

这段代码还有些问题???

public class ProducerConsumerTest {

    private Lock lock = new ReentrantLock();

    private Condition addCondition = lock.newCondition();

    private Condition removeCondition = lock.newCondition();

    private LinkedList<Integer> resources = new LinkedList<>();

    private int maxSize;

    public ProducerConsumerTest(int maxSize) {
        this.maxSize = maxSize;
    }


    public class Producer implements Runnable {

        private int proSize;

        private Producer(int proSize) {
            this.proSize = proSize;
        }

        @Override
        public void run() {
            lock.lock();
            try {
                for (int i = 1; i < proSize; i++) {
                    while (resources.size() >= maxSize) {
                        System.out.println("当前仓库已满,等待消费...");
                        try {
                            addCondition.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("已经生产产品数: " + i + "\t现仓储量总量:" + resources.size());
                    resources.add(i);
                    removeCondition.signal();
                }
            } finally {
                lock.unlock();
            }

        }
    }

    public class Consumer implements Runnable {

        @Override
        public void run() {
            String threadName = Thread.currentThread().getName();
            while (true) {
                lock.lock();
                try {
                    while (resources.size() <= 0) {
                        System.out.println(threadName + " 当前仓库没有产品,请稍等...");
                        try {
                            // 进入阻塞状态
                            removeCondition.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    // 消费数据
                    int size = resources.size();
                    for (int i = 0; i < size; i++) {
                        Integer remove = resources.remove();
                        System.out.println(threadName + " 当前消费产品编号为:" + remove);
                    }
                    // 唤醒生产者
                    addCondition.signal();
                } finally {
                    lock.unlock();
                }
            }

        }
    }

    public static void main(String[] args) throws InterruptedException {
        ProducerConsumerTest producerConsumerTest = new ProducerConsumerTest(10);
        Producer producer = producerConsumerTest.new Producer(100);
        Consumer consumer = producerConsumerTest.new Consumer();
        final Thread producerThread = new Thread(producer, "producer");
        final Thread consumerThread = new Thread(consumer, "consumer");
        producerThread.start();
        TimeUnit.SECONDS.sleep(2);
        consumerThread.start();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值