2 Lock 接口 2.1 复习Synchronized 2.1.1 Synchronized关键字回顾
修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作 用的对象是调用这个方法的对象;
虽然可以使用synchronized来定义方法,但synchronized并不属于方法定义的一部分,因此,synchronized 关键字不能被继承。如果在父类中的某个方法使用了synchronized关键字,而在子类中覆盖了这个方法,在子类中的这个方法默认情况下并不是同步的,而必须显式地在子类的这个方法中加上synchronized关键字才可以。当然,还可以在子类方法中调用父类中相应的方法,这样虽然子类中的方法不是同步的,但子类调用了父类的同步方法,因此,子类的方法也就相当于同步了。
修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。
2.1.2售票操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 class Ticket { private int number = 30 ; public synchronized void sale () { if (number > 0 ) { System.out.println(Thread.currentThread().getName() + " : 卖出: " + number-- + "剩下:" + number); } } } public class SaleTicket { public static void main (String[] args) { Ticket ticket = new Ticket(); new Thread(() -> { for (int i = 0 ; i < 40 ; i++) { ticket.sale(); } }, "AA" ).start(); new Thread(() -> { for (int i = 0 ; i < 40 ; i++) { ticket.sale(); } }, "BB" ).start(); new Thread(() -> { for (int i = 0 ; i < 40 ; i++) { ticket.sale(); } }, "CC" ).start(); } }
2.2 什么是Lock接口 Lock锁实现提供了比使用同步方法和语句可以获得的更广泛的锁操作。它们允许更灵活的结构,可能具有非常不同的属性,并且可能支持多个关联的条件对象。Lock提供了比 synchronized更多的功能。
Lock 与的Synchronized区别:I
Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问;
Lock和synchronized有一点非常大的不同,采用synchronized不需要用户 去手动释放锁,当synchronized方法或者synchronized 代码块执行完之后,系统会自动让线程释放对锁的占用﹔而Lock 则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。
2.3 使用Lock实现卖票例子 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 class LockTicket { private final ReentrantLock lock = new ReentrantLock(); private int number = 30 ; public void sale () { lock.lock(); try { if (number > 0 ) { System.out.println(Thread.currentThread().getName() + " : 卖出: " + number-- + "剩下:" + number); } } finally { lock.unlock(); } } } public class LockSaleTicket { public static void main (String[] args) { LockTicket ticket = new LockTicket(); new Thread(() -> { for (int i = 0 ; i < 40 ; i++) { ticket.sale(); } }, "AA" ).start(); new Thread(() -> { for (int i = 0 ; i < 40 ; i++) { ticket.sale(); } }, "BB" ).start(); new Thread(() -> { for (int i = 0 ; i < 40 ; i++) { ticket.sale(); } }, "CC" ).start(); } }
2.4 小结 Lock和synchronized有以下几点不同:
Lock是一个接口,而synchronized是Java中的关键字,synchronized是内 置的语言实现;
synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;·
Lock 可以让等待锁的线程响应中断,而synchronized却不行,使用 synchronized 时,等待的线程会一直等待下去,不能够响应中断;
通过Lock 可以知道有没有成功获取锁,而synchronized却无法办到。
Lock 可以提高多个线程进行读操作的效率。
在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock 的性能要远远优于synchronized。