一、synchronized 和 ReentrantLock 的区别
synchronized 和 ReentrantLock ,都是加锁方式同步,一个线程正在执行,另一个线程必须等待。
使用分析: ReentrantLock 是Lock 的实现类,在 多线程竞争的环境下,更有性能优势,使用更加的灵活,
但是需要手动的去开启锁和释放锁,尽量放在 try catch finally 中 是适用于修饰代码块
synchronized 不需要手动释放锁,可以作用于 方法和 代码块
1.等待可中断
当持有锁的线程长期不释放的时候,正在等待的线程可以放弃等待,转而处理其他的事情。
具体实例 : 有两个线程 Thread1 和 Thread2 ,Thread1 获得了对象的锁,正在执行任务,另一个线程正在等待,Thread1释放锁。
若使用syncheronized :Thread2 会阻塞 等待。
若使用 ReentrantLock :Thread2 等待长时间后,放弃等待,转而执行其他的任务。
2。公平锁
按照申请的时间先后顺序,依次执行。 synchronized 是非公平锁 ReentrantLock可以在构造方法中传入 true 或 false 来修改是否是 公平锁和 非公平锁
二、非公平锁
// synchronized 是 Java 语言的关键字,是原生语法的互斥,需要JVM 实现 ,
// 而ReentrantLock是JDK1.5之后提供的互斥锁,需要lock() 和unLock(),try()Catch()finally() 配合执行。
private ReentrantLock lock = new ReentrantLock();
public void run() {
lock.lock();
try{
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}finally{
lock.unlock();
}
}
2.1 锁绑定多个条件
ReentrantLock可以同时绑定多个Condition对象,只需多次调用newCondition方法即可。
synchronized中,锁对象的wait()和notify()或notifyAll()方法可以实现一个隐含的条件。但如果要和多于一个的条件关联的时候,就不得不额外添加一个锁。
2.2 线程的安全问题 怎么理解‘
进程中有多个线程同时在执行,这些线程可能会执行同一段代码,多线程的执行结果和单线程的执行结果是一样的。那么就是线程安全的
2.3 synchronized 在编译时怎么实现锁机制?
synchronized 在进行编译的时候,会在同步块的前后,会形成monitorenter 和 monitorexit 两个字节码指令,在执行
monitorenter 时,回先获取锁,得到锁,锁的计数器就是加一,执行完毕计数器就会减一,释放锁。
2.4 什么时候选择 ReentrantLock
确实有 synchronized 没有的特性时, 可中断等候,时间锁等候。
// ThreadPoolExcutor 源码中很地方用到
/**
* Rolls back the worker thread creation.
* - removes worker from workers, if present
* - decrements worker count
* - rechecks for termination, in case the existence of this
* worker was holding up termination
*/
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (w != null)
workers.remove(w);
decrementWorkerCount();
tryTerminate();
} finally {
mainLock.unlock();
}
}
三、非公平锁和公平锁案例分析
// 那个线程先运行,那个线程就先得到锁,非公平锁不管
private void test3() {
Service service = new Service();
ThreadClass tcArray[] = new ThreadClass[10];
for(int i=0;i<10;i++){
tcArray[i] = new ThreadClass(service);
tcArray[i].start();
}
}
public class Service {
ReentrantLock lock = new ReentrantLock(true);
Service() {
}
void getThreadName() {
System.out.println(Thread.currentThread().getName() + " 已经被锁定");
}
}
public class ThreadClass extends Thread{
private Service service;
ThreadClass(Service service) {
this.service = service;
}
public void run(){
System.out.println(Thread.currentThread().getName() + " 抢到了锁");
service.lock.lock();
service.getThreadName();
service.lock.unlock();
}
}
//当ReentrantLock设置true,也就是公平锁时
I/System.out: Thread-5 抢到了锁
I/System.out: Thread-5 已经被锁定
I/System.out: Thread-6 抢到了锁
I/System.out: Thread-6 已经被锁定
I/System.out: Thread-7 抢到了锁
I/System.out: Thread-8 抢到了锁
I/System.out: Thread-7 已经被锁定
I/System.out: Thread-8 已经被锁定
I/System.out: Thread-9 抢到了锁
I/System.out: Thread-9 已经被锁定
I/System.out: Thread-10 抢到了锁
I/System.out: Thread-10 已经被锁定
I/System.out: Thread-11 抢到了锁
I/System.out: Thread-11 已经被锁定
I/System.out: Thread-12 抢到了锁
I/System.out: Thread-12 已经被锁定
I/System.out: Thread-14 抢到了锁
I/System.out: Thread-14 已经被锁定
I/System.out: Thread-13 抢到了锁
I/System.out: Thread-13 已经被锁定