锁:对共享数据加锁使其变为临界区。(排它锁)与共享锁
锁有内部锁(synchronized关键字修饰的)与显式锁(Java.concurrent.locks.Lock接口)。
显式锁与内部锁的比较
各适用环境不同,而非相互代替,内部锁申请或者释放一个锁必须在块或者同一方法中,灵活性更差,但方便,不会导致锁泄露;而显式锁可以跨方法释放锁,灵活性更高,但容易锁泄露,操作不方便,繁琐。同时显示锁支持狠多内部锁不支持的特性。
显式锁之重入锁:
重入锁存在于Java.util.concurrent.locks.ReentrantLock类。
例如:
之所以称为重入锁,是因为可以同一线程重复上锁,即两次上锁,两次释放锁。
中断响应:指两个线程出现死锁可以控制一方放弃申请锁,并释放已获得锁
首先营造一个死锁:
对于这种情况,我们能想到的办法为中断其中一个线程,即:
但这种方式需要在run方法中加isinterrupted作为标志位,只有为TRUE,才可中断,所以:
两种中断比较:
锁申请限时等待:
除了外部通知某个线程中断来处理死锁外,避免死锁还有另外方法:tryLock()
所以,对于上面的死锁问题,我们可以这样解决:
这样,经过几秒后,线程t1与t2都会得到锁资源并顺利执行完毕。
公平锁:
不会产生饥饿现象,synchronized不允许公平锁
说明:ReentrantLock(true)表示公平锁,其看来优美,但要实现公平锁,需要维护一个有序队列,因此公平锁实现成本高,性能低下,因此,一般情况下,锁是非公平的。如果没有特殊要求,也不推荐使用公平锁。
对于系统调度而言,一个线程更倾向于再此获得已经持有的锁,这种分配方式是高效的。
使用公平锁的结果就是,以时间片为单位,交替获得,而不公平锁大部分都是重复输出。
总结:重入锁的几个重要方法:
ReentrantLock()构造方法:实现公平非公平锁
lock():获得锁
lockInterruptibly():获得锁,但优先响应中断
tryLock():获得锁(资源),若锁被占用,返回false
tryLock(long time,TimeUnit unit):给定时间内获得锁
unlock():释放锁,千万不要忘记。