深入浅出Java并发包—锁(Lock)VS同步(synchronized)


今天我们来探讨一下Java中的锁机制。前面我们提到,在JDK1.5之前只能通过synchronized关键字来实现同步,这个前面我们已经提到是属于独占锁,性能并不高,因此JDK1.5之后开始借助JNI实现了一套高效的锁实现!

JDK5以后锁的接口是JUC中的Lock,我们来先看一下他的相关API文档。

 

方法摘要

 void

lock() 
 
获取锁。 如果锁不可用,出于线程调度目的,将禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态。

 void

lockInterruptibly()

         如果当前线程未被中断,则获取锁。

如果锁可用,则获取锁,并立即返回。

如果锁不可用,出于线程调度目的,将禁用当前线程,并且在发生以下两种情况之一以前,该线程将一直处于休眠状态:

 锁由当前线程获得;或者

 其他某个线程中断当前线程,并且支持对锁获取的中断。

如果当前线程:

 在进入此方法时已经设置了该线程的中断状态;或者

 在获取锁时被中断,并且支持对锁获取的中断,

则将抛出 InterruptedException,并清除当前线程的已中断状态。

 Condition

newCondition()
         
返回绑定到此 Lock 实例的新 Condition 实例。

在等待条件前,锁必须由当前线程保持。调用 Condition.await() 将在等待前以原子方式释放锁,并在等待返回前重新获取锁。

 boolean

tryLock() 
 
仅在调用时锁为空闲状态才获取该锁。

如果锁可用,则获取锁,并立即返回值 true。如果锁不可用,则此方法将立即返回值 false

 

此方法的典型使用语句如下:

 

      Lock lock = ...;

      if (lock.tryLock()) {

          try {

              // manipulate protected state

          } finally {

              lock.unlock();

          }

      } else {

          // perform alternative actions

      }

 此用法可确保如果获取了锁,则会释放锁,如果未获取锁,则不会试图将其释放。

 boolean

tryLock(long time, TimeUnit unit)
         
如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁。

如果锁可用,则此方法将立即返回值 true。如果锁不可用,出于线程调度目的,将禁用当前线程,并且在发生以下三种情况之一前,该线程将一直处于休眠状态:

l锁由当前线程获得;或者

l其他某个线程中断当前线程,并且支持对锁获取的中断;或者

l已超过指定的等待时间

 

如果获得了锁,则返回值 true

 

如果当前线程:

l在进入此方法时已经设置了该线程的中断状态;或者

l在获取锁时被中断,并且支持对锁获取的中断,

则将抛出 InterruptedException,并会清除当前线程的已中断状态。

如果超过了指定的等待时间,则将返回值 false。如果 time 小于等于0,该方法将完全不等待。

void

unlock()
          
释放锁。

相对于API来说,我们并不能看出他到底的优点在哪里?我们来看一个实例

package com.yhj.lock;
/**
 * @Described:原子int类型操作测试用例
 * @author YHJ create at 2013-4-26 下午05:58:32
 * @ClassNmae com.yhj.lock.AtomicIntegerTestCase
 */
public interface AtomicIntegerTestCase {
 
    /**
     * ++并返回
     * @return
     * @Author YHJ create at 2013-4-26 下午05:39:47
     */
    int incrementAndGet();
    /**
     * 取值
     * @return
     * @Author YHJ create at 2013-4-26 下午05:39:56
     */
    int get();
}
package com.yhj.lock;
 
 
/**
 * @Described:带同步的测试
 * @author YHJ create at 2013-4-26 下午05:35:35
 * @ClassNmae com.yhj.lock.AtomicIntegerWithLock
 */
public class AtomicIntegerWithSynchronized implements AtomicIntegerTestCase {
   
    private int value;
    private Object lock  = new Object();//为保证两个方法都在同步内 采用对象同步方法
   
    @Override
    public int incrementAndGet(){
       synchronized(lock){
           return ++value;
       }
    }
   
    @Override
    public int get(){
       synchronized(lock){
           return value;
       }
    }
 
}
package com.yhj.lock;
 
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
 
/**
 * @Described:带锁的测试
 * @author YHJ create at 2013-4-26 下午05:35:35
 * @ClassNmae com.yhj.lock.AtomicIntegerWithLock
 */
public class AtomicIntegerWithLock implements AtomicIntegerTestCase{
   
    private int value;
    private Lock lock  = new ReentrantLock();
   
    @Override
    public int incrementAndGet(){
       try {
           lock.lock();
           return ++value;
       }finally{
           lock.unlock();
       }
      
    }
 
    @Override
    public int get(){
       try {
           lock.lock();
           return value;
       }finally{
           lock.unlock();
       }
    }
 
}
package com.yhj.lock;
 
public class Client {
 
    /**
     * 启动并等待线程结束
     * @param threads
     * @throws InterruptedException
     * @Author YHJ create at 2013-4-26 下午05:57:16
     */
    private static void startAndWait(Thread [] threads) throws InterruptedException{
       for(Thread thread:threads)
           thread.start();
       for(Thread thread:threads)
           thread.join();
    }
    /**
     * 准备线程数据
     * @param threads
     * @param testCase
     * @param threadCount
     * @param loopCount
     * @Author YHJ create at 2013-4-26 下午06:01:25
     */
    private static void prepare(Thread [] threads,final AtomicIntegerTestCase testCase,int threadCount,final int loopCount){
       for (int i = 0; i < threadCount; i++) {
           threads[i] = new Thread(){
              @Override
              public void run() {
                  for(int i=0;i<loopCount;++i){
                     testCase.incrementAndGet();
                  }
              }
           };
       }
    }
 
    public static void main(String[] args) throws InterruptedException {
       //前期数据准备
       final int threadCount = 200;//线程数目
       final int loopCount = 100000;//循环次数
       final AtomicIntegerWithLock lockTestCase = new AtomicIntegerWithLock();//测试对象
       final AtomicIntegerWithSynchronized synchronizedtestCase = new AtomicIntegerWithSynchronized();
       //第一波数据准备
       Thread [] threads= new Thread[threadCount];
       prepare(threads, lockTestCase, threadCount, loopCount);
       //第一波启动
       long costTime = 0;
       long start = System.nanoTime();
       startAndWait(threads);
       long end = System.nanoTime();
       costTime = (end-start);
       //第一波输出
       System.out.println("AtomicIntegerWithLock result:"+lockTestCase.get()+" costTime:"+costTime);
       System.out.println("=======我是分割线=======");
       //第二波数据准备
       threads= new Thread[threadCount];
       prepare(threads, synchronizedtestCase, threadCount, loopCount);
       //第二波启动
       costTime = 0;
       start = System.nanoTime();
       startAndWait(threads);
       end = System.nanoTime();
       costTime = (end-start);
       //第二波输出
       System.out.println("AtomicIntegerWithSynchronized result:"+lockTestCase.get()+" costTime:"+costTime);
    }
 
}

运行结果:

AtomicIntegerWithLock result:20000000 costTime:1192257757
=======我是分割线=======
AtomicIntegerWithSynchronized result:20000000 costTime:3955951264

这个例子很简单,200个线程,每次执行10w++操作,很清楚的大家看到,最好的执行结果都是20000000,都能正常的保证数据的一致性,另外我们还能看到一点,就是Lock消耗的时间要比synchronized少,也证明了Lock的性能是要笔synchronized好的!

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM