java同步锁:look 和 synchronized
一 区别 :
1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现,synchronized是在JVM层面上实现的,
不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,
lock是通过代码实现的,要保证锁定一定会被释放,就必须将 unLock()放到finally{} 中;
2)synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,
则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
3)Lock可以让等待锁的线程响应中断,线程可以中断去干别的事务,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;
4)通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
5)Lock可以提高多个线程进行读操作的效率。
在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。
二 lock 接口实现类
public interface Lock { //获取锁,如果锁被暂用则一直等待 void lock(); //用该锁的获得方式,如果线程在获取锁的阶段进入了等待,那么可以中断此线程,先去做别的事 void lockInterruptibly() throws InterruptedException; //注意返回类型是boolean,如果获取锁的时候锁被占用就返回false,否则返回true boolean tryLock(); //比起tryLock()就是给了一个时间期限,保证等待参数时间 boolean tryLock(long time, TimeUnit unit) throws InterruptedException; //释放锁 void unlock(); }
三、唯一实现类:ReentrantLock 获取锁定与三种方式:
a) lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁
b) tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false;
c)tryLock(long timeout,TimeUnit unit), 如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false;
d) lockInterruptibly:如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断
四 synchronized 和 volatile
3.可见性-synchronized java内存模型(JMM)关于synchronized的两条规定: A.线程解锁前,必须把共享变量的最新值刷新到主内存 B.线程加锁时,将清空工作内存中的共享变量的值,从而在使用共享变量时,
需要从主内存中重新读取最新的值(注意:加锁和解锁是同一把锁) 4.可见性-volatile (1).通过加入内存屏障和禁止重排序优化来实现 A.对volatile变量写操作时,会在写操作后加入一条store屏障指令,将本地内存中的共享变量值刷新到主内存 B.对volatile变量读操作时,会在读操作前加入一条load屏障指令,从主内存中读取共享变量
通俗地说就是,volatile变量每次被线程访问时,都强迫从主内存读取该变量的值,而当该变量发生变化时,
又会强迫线程将最新的值刷新到主内存,这样,任何时候不同的线程总能看到该变量的最新值