码迷,mamicode.com
首页 > 编程语言 > 详细

Java-Lock简介

时间:2017-11-12 17:27:33      阅读:165      评论:0      收藏:0      [点我收藏+]

标签:rac   sync   family   性能   并且   关键字   read   nts   pac   

1. 为什么会有Lock的出现

  JDK5之前,我们一般都是通过synchronized来进行加锁操作,但synchronized是一种悲观锁,如果这个获取到锁的线程被阻塞了,但却没有释放锁,其他线程将只能一直无限期的等待着。而Lock可以实现其他线程只等待一定的时间或者能够响应中断。
  又比如,当有多个线程读写文件时,读操作和写操作会发生冲突,写操作和写操作会发生冲突,但是读操作和读操作不会发生冲突。
如果采用synchronized关键字来实现同步的话,就会导致一个问题:如果多个线程都只是进行读操作,所以当一个线程在进行读操作时,其他线程只能等待无法进行读操作。因此就需要一种机制来使得多个线程都只是进行读操作时,线程之间不会发生冲突,通过Lock就可以办到。
  并且通过Lock可以知道线程有没有成功获取到锁,而这点synchronized是无法办到的。

2. Lock不同于synchronized的地方?

  1. Lock锁是通过代码手动实现的,加锁之后,需要我们手动释放锁,不释放的话将很可能会出现死锁问题;而Synchronized是Java的关键字,是由JVM来实现的,synchronized在代码块执行玩或锁定时方法抛出异常的情况下,JVM会自动释放锁;

  2. 通过Lock可以知道有没有成功获取锁,而synchronized却无法办到;

  3. Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断

3. Lock接口方法介绍

package java.util.concurrent.locks;

import java.util.concurrent.TimeUnit;

/*
 * 
 * @since 1.5
 * @author Doug Lea
 */
public interface Lock {

    /**
     * 获取锁操作,如果锁被其他线程占用,则进行等待,该接口使用最多
     */
    void lock();

    /**
     * 中断等待过程,如果线程A拿到了锁,而线程B处于等待中,那么调用该方法能够中断线程B的等待过程。而如果一个线程已经获取到了锁,是不会被该方法中断的。要注意方法抛出了异常
     */
    void lockInterruptibly() throws InterruptedException;

    /**
     * tryLock用来尝试获取锁,如果获取成功,则返回true,如果获取失败(锁被其他线程获取),则返回false,也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。
     * Lock lock = ...;
     * if (lock.tryLock()) {
     *   try {
     *     ...
     *   } finally {
     *     lock.unlock();
     *   }
     * } else {
     *   ...
     * }
     *
     */
    boolean tryLock();

    /**
     * 和tryLock方法类似,但该方法在拿不到锁的时候会等待一定的时间,如果在时间期限内还拿不到锁,就返回false,如果这段时间内拿到了锁,则返回true;
     */
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

    /**
     * 释放锁的方法,一般用于finally中进行释放
     */
    void unlock();

    /***/
    Condition newCondition();
}

注意:

由于Lock要手动释放,因此一般使用Lock都必须在try{}catch{}中进行,在finally中进行释放锁的操作;

Lock lock = ...;
lock.lock();
try {
   //处理任务
} catch (Exception ex) {

} finally {
   lock.unlock(); //释放锁
}

4. 一般我们可以通过ReentrantLock来操作,ReentrantLock是Lock的实现类;

a. testLockInterruptibly

 /**
     * testLockInterruptibly
     *
     * @param thread the thread
     */
    private void testLockInterruptibly(Thread thread) throws InterruptedException{
        if (lock.tryLock()) {
            try {
                System.out.println("当前线程 " + thread.getName() + "获得了锁!");
                Thread.sleep(3000);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                System.out.println("当前线程 " + thread.getName() + "释放了锁!");
                lock.unlock();
            }
        } else {
            System.out.println("线程" + thread.getName() + "中断了!");
            lock.lockInterruptibly();
        }
    }

    public static void main(String[] args) {
        Main main = new Main();
        new Thread(() -> {
            try {
                main.testLockInterruptibly(Thread.currentThread());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() -> {
            try {
                main.testLockInterruptibly(Thread.currentThread());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
当前线程 Thread-0获得了锁!
线程Thread-1中断了!
当前线程 Thread-0释放了锁!

b. testLock,testTryLock:

 /**
     * Test lock.
     *
     * @param thread the thread
     */
    private void testLock(Thread thread) {
        lock.lock();
        try {
            System.out.println("当前线程 " + thread.getName() + "获取了锁!");
        } catch (Exception e) {

        } finally {
            System.out.println("当前线程 " + thread.getName() + "释放了锁!");
            lock.unlock();
        }
    }

    /**
     * Test tryLock.
     *
     * @param thread the thread
     */
    private void testTryLock(Thread thread) {
        if (lock.tryLock()) {
            try {
                System.out.println("当前线程 " + thread.getName() + "获得了锁!");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                System.out.println("当前线程 " + thread.getName() + "释放了锁!");
                lock.unlock();
            }
        } else {
            System.out.println("有人占着锁,线程" + thread.getName() + "获取不了锁");
        }
    }
    
    public static void main(String[] args) {
        Main main = new Main();
       
        new Thread(() -> main.testLock(Thread.currentThread())).start();
        new Thread(() -> main.testLock(Thread.currentThread())).start();
    }

  另一个Lock是读写锁:ReadWriteLock,该接口只有两个方法,一个用来获取读锁,一个用来获取写锁。也就是说将文件的读写操作分开,分成2个锁来分配给线程,从而使得多个线程可以同时进行读操作。

而ReentrantReadWriteLock则实现了ReadWriteLock接口。

  所以,在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。

 

本文参考自:https://www.cnblogs.com/baizhanshi/p/6419268.html

Java-Lock简介

标签:rac   sync   family   性能   并且   关键字   read   nts   pac   

原文地址:http://www.cnblogs.com/xiaozhang2014/p/7821953.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!