首先說一下 lock 和 synchronized 的區別:
1:lock 是 java 語言的一個藉口,synchronized 是 java 的關鍵字,是語言特性
2:synchronized 在 發生異常時,可以自動釋放鎖,因此不會發生死鎖情況,而 lock 只能通過顯式的 unlock() 釋放,否則容易發生死鎖情況。
3:lock 可以讓等待的線程相應中斷,而synchronized 會讓等待的線程一直等待下去。
4:lock 可以知道是否成功獲取鎖,而 synchronized 卻不知道
5:lock 可以有效提高併發讀的效率,而 synchronized 只能進行串行操作。
總的來講:如果資源競爭不激烈,兩者的性能差不多,如果資源競爭比較激烈,lock 的性能明顯優於synchronized。
具體測試代碼,有點雜。
package concurrent;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/*
* @author: wjf
* @version: 2016年3月26日 上午11:40:08
*/
public class TestLock {
private Lock lock=new ReentrantLock();
private ReentrantReadWriteLock rwl=new ReentrantReadWriteLock();
private ArrayList<Integer> list=new ArrayList<Integer>();
public synchronized void get(Thread thread){
long start=System.currentTimeMillis();
while(System.currentTimeMillis()-start<=10){
System.out.println(thread.getName()+"is reading");;
}
System.out.println(thread.getName()+"reading is done");
}
public void get2(Thread thread){
rwl.readLock().lock();
try{
long start=System.currentTimeMillis();
while(System.currentTimeMillis()-start<=1){
System.out.println(thread.getName()+"is reading");
}
System.out.println(thread.getName()+"reading is done");
}finally{
rwl.readLock().unlock();
}
}
public void insert(Thread thread){
// 主要 如果這個鎖聲明在這個地方則沒有任何效果,因爲他是 局部的,每個thread 都會聲明一個不同的鎖
//private Lock lock=new ReentrantLock();
lock.lock();
try{
System.out.println(thread.getName()+"得到了鎖");
for(int i=0;i<5;i++){
list.add(i);
}
System.out.println(list.size());
}catch(Exception x){
}finally{
System.out.println(thread.getName()+"釋放了鎖");
lock.unlock();
}
}
//測試 trylock()
public void insert2(Thread thread) throws InterruptedException{
// tryLock() 如果 無法獲取鎖 則,直接退出
//lock.tryLock(time, unit) 則會等待一定的時間
if(lock.tryLock(1, TimeUnit.MICROSECONDS)){
try{
System.out.println(thread.getName()+"得到了鎖");
for(int i=0;i<100000;i++){
list.add(i);
}
System.out.println(list.size());
}catch(Exception x){
}finally{
System.out.println(thread.getName()+"釋放了鎖");
lock.unlock();
}
}
else{
System.out.println(thread.currentThread()+"獲取鎖失敗");
}
}
public void insert3(Thread thread) throws InterruptedException{
lock.lockInterruptibly();
// lock.lock();
try{
System.out.println(thread.getName()+"獲得了鎖");
long startTime=System.currentTimeMillis();
for(;;){
if(System.currentTimeMillis()-startTime>10000){
break;
}
}
}finally{
System.out.println(Thread.currentThread().getName()+"執行finally");
lock.unlock();
System.out.println(thread.getName()+"釋放了鎖");
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
TestLock lock=new TestLock();
new Thread(){
public void run(){
lock.get2(Thread.currentThread());
}
}.start();
new Thread(){
public void run(){
lock.get2(Thread.currentThread());
}
}.start();
/* test interrupt()
*
MyThread thread1=new MyThread(lock);
MyThread thread2=new MyThread(lock);
thread1.start();
thread2.start();
try{
Thread.sleep(2000);
}catch(InterruptedException e){
e.printStackTrace();
}
thread2.interrupt();
*/
// new Thread(){
// public void run(){
// try {
// lock.insert2(Thread.currentThread());
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// }
// }.start();
// new Thread(){
// public void run(){
// try {
// lock.insert2(Thread.currentThread());
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// }
// }.start();
}
}
class MyThread extends Thread{
private TestLock test=null;
public MyThread(TestLock test){
this.test=test;
}
public void run(){
try{
test.insert3(Thread.currentThread());
}catch(Exception e){
System.out.println(Thread.currentThread().getName()+"被中斷了");
}
}
}
補充一點關於 synzhronized 的 內容
關於可重入性:(reentrant)
lock 和 synchronized 都是可重入的。
可重入性實際上表明瞭鎖的分配機制是基於線程的而不是基於方法的。比如下面的例子:
加入method1 獲取了鎖,調用method2() ,則不需要再去申請鎖,就可以執行method2(),
public synchronized void method1(){
method2()
}
public synchronized void method2(){
//
}