synchronized是java中的一个关键字,也就是说是Java语言内置的特性。那么为什么会出现Lock呢?
如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁,而这里获取锁的线程释放锁会有三种情况:
1)获取锁的线程执行完了该代码块,然后线程释放对锁的占有;
2)线程执行发生异常,此时JVM会让线程自动释放锁。
3)这个主要是在等待唤醒机制里面的wait()方法,//在等待的时候立即释放锁,方便其他的线程使用锁。而且被唤醒时,就在此处唤醒,
那么如果这个获取锁的线程由于要等待IO或者其他原因(比如调用sleep方法)被阻塞了,但是又没有释放锁,其他线程便只能干巴巴地等待,试想一下,这多么影响程序执行效率。因此我们需要不论程序的代码块执行的如何最终都将锁对象进行释放,方便其他线程的执行。(此处后面有一个简单的demo起始就是将锁对象人工的释放而且是在finally里面的执行)
虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,同时为了更好地释放锁。
为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock。
另外,通过Lock可以知道线程有没有成功获取到锁。这个是synchronized无法办到的。
总结一下,也就是说Lock提供了比synchronized更多的功能。但是要注意以下几点:
1)Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问;
2)synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中
3)在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,
但是ReetrantLock的性能能维持常态;
一、Lock锁的简单使用
1 import java.util.concurrent.locks.Lock; 2 import java.util.concurrent.locks.ReentrantLock; 3 4 public class SellTicket implements Runnable { 5 6 // 定义票 7 private int tickets = 100; 8 9 // 定义锁对象 10 private Lock lock = new ReentrantLock(); 11 12 @Override 13 public void run() { 14 while (true) { 15 try { 16 // 加锁 17 lock.lock(); 18 if (tickets > 0) { 19 try { 20 Thread.sleep(100); 21 } catch (InterruptedException e) { 22 e.printStackTrace(); 23 } 24 System.out.println(Thread.currentThread().getName() 25 + "正在出售第" + (tickets--) + "张票"); 26 } 27 } finally { 28 // 释放锁 29 lock.unlock(); 30 } 31 } 32 } 33 //注意 这种写法 就是为了防止程序异常 而不放锁 而且还可以清晰的看到那些线程拿到了锁 34 }
出异常的测试 多线程
1 import java.util.concurrent.locks.Lock; 2 import java.util.concurrent.locks.ReentrantLock; 3 4 public class SellTicket implements Runnable { 5 6 // 定义票 7 private int tickets = 100; 8 9 // 定义锁对象 10 private Lock lock = new ReentrantLock(); 11 12 @Override 13 public void run() { 14 while (true) { 15 try { 16 // 加锁 17 lock.lock(); 18 if (tickets > 0) { 19 try { 20 Thread.sleep(100); 21 } catch (InterruptedException e) { 22 e.printStackTrace(); 23 } 24 System.out.println(Thread.currentThread().getName() 25 + "正在出售第" + (tickets--) + "张票"); 26 }
int i=1/0; 27 } finally { 28 // 释放锁 29 lock.unlock(); 30 } 31 } 32 } 33 //注意 这种写法 就是为了防止程序异常 而不放锁 而且还可以清晰的看到那些线程拿到了锁 34 }
下面是测试类
1 public class RunnableDemo { 2 public static void main(String[] args) { 3 SellTicketsRunnable str = new SellTicketsRunnable(); 4 5 Thread tr1 = new Thread(str, "tr1"); 6 Thread tr2 = new Thread(str, "tr2"); 7 Thread tr3 = new Thread(str, "tr3"); 8 9 // 10 tr1.start(); 11 tr2.start(); 12 tr3.start(); 13 } 14 }