进行同步控制,不止有synchronzied一种手段,还有重入锁、读写锁等等,更好地线程同步进行控制。

一、重入锁
1、什么是重入锁
重入锁可以代替synchronized关键字、Object.wait()、Object.notify(),并进行了扩展。
重入锁有着显示的操作过程,必须手动指定何时加锁,何时释放锁,因此其灵活性要优于synchronized。要注意的是,在退出临界区时必须要记得释放锁,否则将导致其他线程没有办法访问临界区。
重入的意思是,一个线程可以连续多次获取同一个锁,并且要释放相同次数的锁。
重入锁采用java.util.concurrent.locks.ReentrantLock类实现。

2、重入锁重要API
a.中断响应lockInterruptibly()
由于线程可能会中断,那么在等待锁的过程中,线程可以根据需要取消对锁的需求。也就是说,在对线程调用interrupt()终端方法后,该线程会响应而中断。
b.限时等待tryLock()
如果无法判断一个线程为什么迟迟拿不到锁,可能是因为死锁,也可能因为饥饿。我们可以通过限时等待方法,给定一个等待时间,超时自动放弃,进行优化。举例:

lock.tryLock(5,TimeOut.SECONDS);

表示尝试获取锁等待5秒,若超时未获得锁,则返回false。
若不带参数直接调用,表示尝试获取锁,并立即返回一个布尔值。
c.公平锁
公平锁表示按照时间先后顺序,使线程排队获取锁,其特点是不会产生饥饿现象,实现公平锁需要系统维护一个有序队列,实现成本较高,性能低下。与此相对,synchronized关键字对锁的控制就是非公平的。
通过以下方式可将一个重入锁定义为公平锁:

public  static ReentrantLock  lock=new ReentrantLock(true);  //true 表示lock为公平锁

二、Condition接口
Condition与重入锁的关系,如同synchronized与Object.wait()、Object.notify()之间的关系。
Condition的几个API:

1、await():使当前线程等待,同时释放当前锁,当其他线程中使用signal()或signalAll()时,线程会重新获得锁并继续执行,或者线程中断时跳出等待。
 2、awaitUninterruptibly():与await()类似,不同在于它不会在等待过程中响应中断。
 3、signal():唤醒一个正在等待的线程。
 4、signalAll():唤醒所有正在等待的线程。

三、读写锁
采用读写分离锁,可以有效减少锁竞争,提升系统性能。读写锁允许多个线程同时读,是非阻塞的,访问约束情况如下:
读读不互斥:读读之间不阻塞。
读写互斥:读阻塞写,写阻塞读。
写写互斥:写写阻塞。
以下方式可以定义一个读写锁:

public static ReenTrantReadWriteLock readWriteLock=new ReentrantReadWriteLock();

四、线程阻塞工具类:LockSupport
它可以在线程内任意位置让线程阻塞。与Thread.suspend()相比,它弥补了由于resume()方法导致的线程无法继续执行的情况。
通过静态方法park()可以阻塞当前线程,我们可能无法保证unpark()方法发生在park()方法之后,但是由于LockSupport采用类似信号量的机制,它为每个线程准备了一个许可,如果许可可用,那么park()方法立即返回,并消费这个许可(许可变为不可用),unpark()则可以把一个许可变为可用,许可不可累加,只有一个。
park()方法挂起的线程不会像suspend()方法给出一个Runable状态,而是一个明确的WAITING状态,并表示是由于park()方法引起的。