线程不安全
解决方案1:同步代码块
格式: synchronized(锁对象){} //java中任何对象都可以作为锁对象加上锁标记
100个对象要上同个锁才能合理
解决方案2:同步方法(还需了解)
public synchronized boolean sale(){
//不是静态就是this 是静态就是类名.class
}
解决方案3:显示锁Lock
同步代码块和同步方法都属于隐式锁
显示锁Lock子类 ReentrantLock()
private Lock lo = new ReentrantLock(); //自己创建一把锁
lo.lock(); //上锁
lo.unlock(); //解锁
显示锁和隐式锁的区别
java中隐式锁:synchronized;显示锁:lock
1.构成不同
Synchronized:java中的关键字,是由JVM来维护的,是JVM层面的锁。
Lock:是jdk5之后出现的具体的类,使用lock是调用对应的API,是API层面的锁。
synchronized的底层是通过monitorenter进行加锁
(底层是通过monitor对象来完成的,其中的wait/notify等方法也是依赖于monitor对象的。
只有在同步代码块或者是同步方法中才可以调用wait/notify等方法的。因为只有在同步块或者是同步方法中,JVM才会调用monitory对象的)
通过monitorenter来初始化和获取锁,monitorexit来释放锁的。
而lock是通过调用对应的API方法来获取锁和释放锁的。
2.使用方式不同
所谓的显示和隐式就是在使用的时候,使用者要不要手动写代码去获取锁和释放锁的操作。
我们大家都知道,在使用synchronized关键字的时候,我们使用者根本不用写其他的代码,然后程序就能够获取锁和释放锁了。
那是因为当sync代码块执行完成之后,系统会自动的让程序释放占用的锁。Sync是由系统维护的,如果非逻辑问题的话话,是不会出现死锁的。
在使用lock的时候,我们使用者需要手动的获取和释放锁。如果没有释放锁,就有可能导致出现死锁的现象。
手动获取锁方法:lock.lock()。释放锁:unlock方法。需要配合tyr/finaly语句块来完成
3.等待是否可以中断
Synchronized是不可中断的,除非抛出异常或正常运行完成
Lock是可以中断的。
中断方式:
(1)、tryLock
boolean tryLock()
仅在调用时锁为空闲状态才获取该锁。
如果锁可用,则获取锁,并立即返回值 true。如果锁不可用,则此方法将立即返回值 false。
此用法可确保如果获取了锁,则会释放锁,如果未获取锁,则不会试图将其释放。
返回值:如果获取了锁,则返回 true;否则返回 false。
(1.1)、tryLock
boolean tryLock(long time,
TimeUnit unit)
throws InterruptedException
如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁。
如果锁可用,则此方法将立即返回值 true。如果锁不可用,出于线程调度目的,将禁用当前线程,并且在发生以下三种情况之一前,该线程将一直处于休眠状态:
锁由当前线程获得;或者
其他某个线程中断当前线程,并且支持对锁获取的中断;或者
已超过指定的等待时间
如果获得了锁,则返回值 true。
如果当前线程:在进入此方法时已经设置了该线程的中断状态;或者
在获取锁时被中断,并且支持对锁获取的中断,
则将抛出 InterruptedException,并会清除当前线程的已中断状态。
如果超过了指定的等待时间,则将返回值 false。如果 time 小于等于 0,该方法将完全不等待。
实现注意事项:
在某些实现中可能无法中断锁获取,即使可能,该操作的开销也很大。程序员应该知道可能会发生这种情况。在这种情况下,该实现应该对此进行记录
相对于普通方法返回而言,实现可能更喜欢响应某个中断,或者报告出现超时情况。
Lock 实现可能可以检测锁的错误用法,例如,某个调用可能导致死锁,在特定的环境中可能抛出(未经检查的)异常。该 Lock 实现必须对环境和异常类型进行记录。
参数:
time - 等待锁的最长时间
unit - time 参数的时间单位
返回:
如果获得了锁,则返回 true;如果在获取锁前超过了等待时间,则返回 false
抛出:
InterruptedException - 如果在获取锁时,当前线程被中断(并且支持对锁获取的中断
(2)、调用lockInterruptibly()放到代码块中,然后调用interrupt()方法可以中断
4.加锁的时候是否可以公平
Locks 是公平锁
Lock lo = new ReentrantLock(true); //公平锁 就是谁先来谁得到这个锁
显示锁lo:fair参数为true,就表示是公平锁,默认(不填)是false.
Synchronized是不公平锁
即排队抢锁,同时抢锁都是不公平锁。
5.锁绑定多个条件来condition
Synchronized:没有,要么随机唤醒一个线程;要么是唤醒所有等待的线程。
Lock:用来实现分组唤醒需要唤醒的线程,可以精确的唤醒,而不是像synchronized那样,不能精确唤醒线程。
6.从性能比较
7.从使用锁的方式比较
一些内容转载自https://www.cnblogs.com/kaigejava/p/12710602.html
https://blog.51cto.com/2839840/2326202