一:ReentrantLock类
ReentrantLock类可以实现线程间同步互斥,嗅探锁定,多路分支通知等功能。
调用ReentrantLock对象的Lock()方法获取锁,调用UnLock()方法释放锁。
使用Condition实现等待/通知:
使用Condition具有良好的灵活性,实现多路通知功能,也就是在一个Lock对象里面创建多个Condition(即对象监视器)实例,线程对象可以注册在指定的Condition中,从而有选择的进行线程通知,在调度线程上更加灵活。
而synchronized就相当于整个Lock对象中只有一个单一的Condition对象,所有的线程都注册在它一个对象的身上。线程开始notifyAll()时,需要通知所有的WAITING线程,没有选择权,会出现效率问题。
private ReentrantLock lock = new ReentrantLock( );
private Condition condition = lock.newCondition( );
先调用Lock.lock()代码获得同步监视器,然后再调用condition.await( ).使当前执行任务的线程进入等待WAITING状态。
try-catch-finally语句中 condition.await( )方法放在代码出口(及try代码块的最后一行),在finally代码块中Lock.UnLock( )。
service.signalAll( )唤醒所有线程。---》可指定对象
公平锁和非公平锁
公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的FIFO先进先出顺序。结果有序。
非公平锁就是一种获取锁的抢占机制,是随机获得锁的,和公平锁不一样的是先来的不一定先得到锁,这种方式可能造成某些线程一直得不到锁,结果是不公平的。结果无序。
方法getHoldCount(),getQueueLength()和getWaitQueueLength()
1)方法getHoldCount()的作用是查询当前线程保持此锁定的个数,也就是调用Lock()方法的次数。
2)方法getQueueLength()的作用是返回正等待获取此锁的线程估计数。等待Lock释放的线程个数。
3)方法getWaitQueueLength()的作用是返回等待此锁定相关的给定条件Condition的线程估计数。
方法hasQueuedThread(),hasQueuedThread()和hasWaiters()
1)Boolean hasQueuedThread()的作用是查询是否有线程正在等待获取此锁定。
2)Boolean hasWaiters()的作用是查询是否有线程正在等待获取此锁定有关的condition条件。
方法isFair(),isHeldByCurrentThread()和isLocked()
1)Boolean isFair()判断是否为公平锁。在默认情况下,ReentrantLock类使用的是非公平锁。
2)Boolean isHeldByCurrentThread()的作用是查询当前线程是否保持此锁定。
3)Boolean isLocked()的作用是查询此锁定是否由任意线程保持。
方法LockInterruptibly(),tryLock()和tryLock(Long timeout ,TimeUnit unit)
1)方法void LockInterruptibly()的作用是:如果当前线程未被中断,则获取锁定,如果已经中断则出现异常。
lock.interrupt( )线程中断后,Lock()不出现异常,正常执行。
lock.Lockinterruptibly( )线程中断后,Lock()报异常,停止执行。
2)方法Boolean tryLock()的作用是:仅在调用时锁定未被另一个线程保持的情况下,才获取该锁定。
3)方法Boolean tryLock(Long timeout ,TimeUnit unit)的作用是:如果在锁定给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁定。
方法awaitUninterruptibly()的使用
await出现异常,awaitUninterruptibly正常运行无异常。
方法awaitUntil()的使用
指定时间唤醒,但在是等待时间内,可被其他线程提前唤醒。
使用Condition实现顺序执行
使用CondiTion对象可以对线程执行的业务进行排序规划。
二:ReentrantReadWriteLock类
ReentrantLock类具有完全互斥排他的效果,即同一时间只有一个线程在执行ReentrantLock.lock()方法后面的任务。保证了实例变量的线程安全性。
ReentrantReadWriteLock读写锁
1)一个是读操作相关的锁,也成为共享锁,
2)另一个是写操作的锁,也叫排它锁。
多个读锁之间不互斥,读锁与写锁互斥,写锁与写锁互斥。多个Thread可以同时进行读取操作,但是同一时刻只允许一个Thread进行写入操作。
使用写锁代码Lock.readLock( ),允许多个线程同时执行Lock()方法后面的代码。
使用写锁代码Lock.writeLock( )的效果就是同一时间只允许一个线程执行Lock()方法后面的代码。
定时器Timer的使用
Timer的主要作用就是设置计划任务,但封装的类是TimerTask类,执行计划任务的代码放入TimerTask的子类中,Timer是一个抽象类。
方法schedule(TimerTask task,Date time)该方法的作用是在指定的日期执行一次某一任务。
1)执行任务的时间晚于当前时间:在未来执行
创建一个Timer就是启动一个新的线程,这个新启动的线程并不是守护线程,它不会执行完就关闭,需要将创建Timer的线程改为守护线程。new Timer(true);
2)计划时间早当前时间:提前运行
3)多个TimerTask任务执行:顺序执行
方法schedule(TimerTask task,Date firstTime long period)该方法的作用是在指定的日期之后,按指定的间隔周期性地无限循环地执行某一任务。
1)执行任务的时间晚于当前时间:在未来执行
2)计划时间早当前时间:提前运行
3)任务执行时间被延时:任务延时但还是一个一个执行(即不能保证执行时间与预期时间一致)
TimerTask类的cancel()方法
TimerTask类中的cancel()方法的作用是将自身从任务队列中清除,其他任务不收影响。
Timer类的cancel()方法
和TimerTask类中的cancel()方法清除自身不同,Timer类中的cancel()方法的作用是将任务队列中的全部任务清空,并且进程任务被销毁。
注意:Timer类中的cancel()方法的有时并不一定会停止执行任务计划,而会正常执行。这是因为Timer类中的cancel()方法有时并没有争抢到queue锁,所以其他任务还会继续正常执行。
方法schedule(TimerTask task,long period)以执行当前方法的时间为参考时间,在此时间基础上延迟指定的毫秒数后执行一次TimerTask任务。
方法schedule(TimerTask task,long delay,long period)以执行当前方法的时间为参考时间,在此时间基础上延迟指定的毫秒数,再以某一间隔时间无限次数地执行一次某一任务。
方法scheduleAtFixedRate(TimerTask task,Date firstTime long period)
相同点:
1、方法schedule 和方法 scheduleAtFixedRate 都会按顺序执行,所以不用考虑非线程安全的情况。
2、方法schedule 和方法 scheduleAtFixedRate 如果执行任务的时间没有被延迟,那么下一次任务的执行时间参考的是上一次的任务的"开始"时的时间来计算的。
3、方法schedule 和方法 scheduleAtFixedRate 如果执行任务的时间被延迟了,那么下一次任务的执行时间参考的是上一次任务"结束"时的时间来计算。
1)执行schedule方法任务不延时:则下一次执行任务的时间是上一次任务的开始时间加上delay时间。
2)执行schedule方法任务延时:则下一次执行任务的时间是上一次任务“结束”时的开始时间为参考来计算。
3)schedule方法不具有追赶执行性
1)执行scheduleAtFixedRate方法任务不延时:则下一次执行任务的时间是上一次任务的开始时间加上delay时间。
2)执行scheduleAtFixedRate方法任务延时:则下一次执行任务的时间以上一次任务“结束”时的时间为参考来计算。
3)scheduleAtFixedRate方法具有追赶执行性
就是如果任务 在周期性运行过程中被打断了,scheduleAtFixedRate 会尝试把之前落下的任务补上运行。