Java 锁

16-12-04 yunduan
    

什么是线程安全?

当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象就是线程安全的。代码本省封装了所有必要的正确性保障手段(互斥同步等),令调用者无需关心多线程的问题,更无需自己实现任何措施来保证多线程的正确调用。

如何来实现线程安全?

我们应用最多的就是互斥锁;

java的互斥锁的主要有synchronized,和JUC 中的lock两种;

加锁的原理是

对象上有一个是否加锁的标志位和锁计数器,一个线程访问了一个锁住的代码后,获取锁,这时候会修改加锁标志位为“已加锁”,锁计数器=1;同一个线程访问多个synchronized代码是不需要重复获取锁的,也就是说同一个线程是不会出现死锁的问题。只是 锁计数器 = 锁计数器+1;当锁计数器=0时,会释放该对象的锁。如果synchronized修饰的是一个静态方法或class,这种情况是类锁。而区别于前面的对象锁了。

synchronized 主要用来修饰方法,或代码块,在{}中的代码是需要获取锁以后才能访问的,

synchronized的加锁和锁的释放是有jvm管理的,不需要我们代码控制。

ReentrantLock的高级特性有那几个?

1、等待可中断,当持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,改为处理其他事情;

2、可以实现公平锁,公平锁指多个线程在等待同一个锁时,必须按照申请锁的顺序依次获得锁,synchronized是非公平锁,ReentrantLock默认也是非公平的,只不过可以通过构造函数来制定实现公平锁;

3、锁绑定多个条件,ReentrantLock对象可以同时绑定多个Condition对象,在synchronized中,锁对象的wait/notify/notifyall方法可以实现一个隐含的条件,如果要多一个条件关联的时候,就需要额外的增加一个锁;

关于锁的几个使用建议?

1、使用并发包中的类,并发包中的类大多数采用了lock-free等算法,减少了多线程情况下的资源的锁竞争,因此对于线程间的共享操作的资源而言,应尽量使用并发包中的类来实现;

2、尽可能少用锁,没必要用锁的地方就不要用了;

3、拆分锁,即把独占锁拆分为多把锁(这个不一定完全适用);