java.util.concurrent.locksjava
对于线程安全咱们前面使用了synchronized关键字,对于线程的协做咱们使用Object.wait()和Object.notify()。在JDK1.5中java为咱们提供了Lock来实现与它们相同的功能,而且性能优于它们,在JDK1.6时,JDK对synchronized作了优化,在性能上两种方式差距不大了。安全
synchronized修饰的代码块,当一个线程获取了对应的锁,并执行该代码块时,其余线程便只能一直等待,等待获取锁的线程释放锁,若是没有释放则须要无限的等待下去。获取锁的线程释放锁只会有两种状况:性能
一、获取锁的线程执行完了该代码块,而后线程释放对锁的占有。优化
二、线程执行发生异常,此时JVM会让线程自动释放锁。spa
Lock与synchronized对比:线程
一、Lock不是Java语言内置的,synchronized是Java语言的关键字,所以是内置特性。Lock是一个类,经过这个类能够实现同步访问。code
二、synchronized不须要手动释放锁,当synchronized方法或者synchronized代码块执行完以后,系统会自动让线程释放对锁的占用;而Lock则必需要用户去手动释放锁,若是没有主动释放锁,就有可能致使出现死锁现象。blog
public interface Lock { //用来获取锁。若是锁已被其余线程获取,则进行等待。 void lock(); // 当经过这个方法去获取锁时,若是线程正在等待获取锁,则这个线程可以响应中断,即中断线程的等待状态 void lockInterruptibly() throws InterruptedException; //它表示用来尝试获取锁,若是获取成功,则返回true,若是获取失败(即锁已被其余线程获取),则返回false boolean tryLock(); //与tryLock()方法是相似的,只不过区别在于这个方法在拿不到锁时会等待必定的时间,在时间期限以内若是还拿不到锁,就返回false。若是若是一开始拿到锁或者在等待期间内拿到了锁,则返回true。 boolean tryLock(long time, TimeUnit unit) throws InterruptedException; //释放锁 void unlock(); Condition newCondition(); }
一、Lock与unlock
Lock用于获取锁,但它不会主动释放锁因此须要与unlock()配合使用。通常在使用Lock时必须在try{}catch{}块中进行,而且将释放锁的操做放在finally块中进行,以保证锁必定被被释放,防止死锁的发生。接口
package com.jalja.base.threadTest; import java.util.concurrent.locks.ReentrantLock; public class LockTest implements Runnable{ public static ReentrantLock lock=new ReentrantLock(); public static int c=0; public void run() { for(int i=0;i<1000;i++){ lock.lock();//获取锁 try { System.out.println(Thread.currentThread().getName()+"得到锁"); System.out.println(Thread.currentThread().getName()+"====>"+c); c++; } catch (Exception e) { e.printStackTrace(); }finally{ System.out.println(Thread.currentThread().getName()+"释放锁"); lock.unlock();//释放锁 } } } public static void main(String[] args) { LockTest lt=new LockTest(); Thread thread1=new Thread(lt); Thread thread2=new Thread(lt); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(c); } }
注意:同一个线程能够连续得到同一把锁,但也必须释放相同次数的锁。容许下面的写法get
lock.lock();//获取锁 lock.lock(); lock.lock(); try { System.out.println(Thread.currentThread().getName()+"得到锁"); System.out.println(Thread.currentThread().getName()+"====>"+c); c++; } catch (Exception e) { e.printStackTrace(); }finally{ System.out.println(Thread.currentThread().getName()+"释放锁"); lock.unlock();//释放锁 lock.unlock();//释放锁 lock.unlock();//释放锁 }
二、获取锁等待时间tryLock(long time, TimeUnit unit)
若是你约朋友打篮球,约定时间到了你朋友尚未出现,你等1小时后仍是没到,我想你确定会扫兴的离去。对于线程来讲也应该时这样的,由于一般咱们是没法判断一个线程为何会没法得到锁,但咱们能够给该线程一个获取锁的时间限制,若是到时间尚未获取到锁,则放弃获取锁。
package com.jalja.base.threadTest; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; public class TryLockTest implements Runnable{ public static ReentrantLock lock=new ReentrantLock(); private static int m=0; public void run() { try { if(lock.tryLock(1, TimeUnit.SECONDS)){//设置获取锁的等待时长1秒 System.out.println(Thread.currentThread().getName()+"得到锁"); m++; //Thread.sleep(2000);//设置休眠2秒 }else{ System.out.println(Thread.currentThread().getName()+"未得到锁"); } } catch (Exception e) { e.printStackTrace(); }finally{ if(lock.isHeldByCurrentThread()){ lock.unlock(); } } } public static void main(String[] args) { TryLockTest thread1=new TryLockTest(); TryLockTest thread2=new TryLockTest(); Thread th1=new Thread(thread1); Thread th2=new Thread(thread2); th1.start(); th2.start(); try { //让main线程等待th一、th2线程执行完毕后,再继续执行 th1.join(); th2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(m); } }
执行结果:
Thread-0得到锁 Thread-1得到锁 2
该代码就是让线程在锁请求中,最多等待1秒,若是超过一秒没有得到锁就返回false,若是得到了锁就返回true,根据执行结果能够看出Thread-1线程在1秒内得到了锁。
咱们开启注释 //Thread.sleep(2000);就会发现Thread-1或Thread-0必定会有一个是未得到锁,这是由于占用锁的线程时间是2秒,而等待锁的线程等待时间是1秒,因此在1秒后的瞬间它就放弃了请求锁操做。