在上一篇文章中,我们谈到了采用synchronized来实现多线程同步,在Java中还一种实现多线程同步的方法,那就是Lock。下面主要谈谈这两种多线程同步的区别。
1、synchronized是在JVM层面实现的,系统可以监控锁的释放与否。
2、ReentrantLock使用代码实现的,系统无法自动释放锁,需要在代码中finally子句中显式释放锁lock.unlock()。
3、相对于synchronized,ReentrantLock还多了 锁投票,定时锁等候和中断锁等候。
例:线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定,
如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断
如果 使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情。
4、synchronized是由系统监控,对于业务不是很熟悉的开发者来说,用起来更省心,但是在并发量比较高的情况下,其性能下降很严重,此时ReentrantLock是个不错的方案。
用Lock实现同步例子:
public class Consumer implements Runnable {
private Lock lock;
public Consumer(Lock lock) {
this. lock = lock;
}
@Override
public void run() {
// TODO Auto-generated method stub
int count = 10;
while( count > 0 ) {
try {
lock.lock();
count --;
System. out.print( "B");
} finally {
lock.unlock(); //主动释放锁
try {
Thread. sleep(91L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
public class Producer implements Runnable{
private Lock lock;
public Producer(Lock lock) {
this. lock = lock;
}
@Override
public void run() {
// TODO Auto-generated method stub
int count = 10;
while (count > 0) {
try {
lock.lock();
count --;
System. out.print( "A");
} finally {
lock.unlock();
try {
Thread. sleep(90L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
调用代码:
public class Test {
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Consumer consumer = new Consumer(lock);
Producer producer = new Producer(lock);
new Thread(consumer).start();
new Thread( producer).start();
}
}
忠告:多线程同步的时候,优先考虑synchronized,如果有特殊需要,再进一步优化。ReentrantLock和Atomic如果用的不好,不仅不能提高性能,还可能带来灾难。