浅谈Lock

javaLock是一个接口:
在这里插入图片描述
根据方法名字,基本知道方法的主要用途。命名很重要。。。

ReentrantLock

,可重入锁,ReentrantLock是唯一实现了Lock接口的类,简单的测试:
在这里插入图片描述
Lock应该放在成员变量里面,如果放在方法里面,每次执行都会new一个新的Lock,就不是同一个lock了
在这里插入图片描述
lock放在方法里面,执行出来多个线程在获得锁:
在这里插入图片描述
tryLock() & tryLock(long time, TimeUnit unit)顾名思义,就是尝试获取锁,可以加时间,tryLock(long time, TimeUnit unit) 能够响应中断,即支持对获取锁的中断,但是但尝试获取一个内部锁(synchronized)的操作是不能被中断,返回的是boolean类型这里可以进行判断,如果获取到了锁,则进行啥,若没有获取到锁执行啥,
在这里插入图片描述
测试代码:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockTest {

    private Lock lock = new ReentrantLock();
    /**
     *     true 表示 ReentrantLock 的公平锁
     */
    private ReentrantLock lock = new ReentrantLock(true);

    public static void main(String[] args) {
        //简单的使用
        test1();
        //trylock
        test2();
        //中断锁
        test3();
    }

    public static void test1() {
        LockTest lockTest = new LockTest();
        for (int i = 0; i < 10; i++) {
            //线程1
            new Thread(() -> {
                lockTest.method1(Thread.currentThread());
            }, i + "").start();
        }
    }

    //需要参与同步的方法
    private void method1(Thread thread) {
        //错误
//        Lock lock = new ReentrantLock();
        lock.lock();
        try {
            System.out.println("线程名" + thread.getName() + "获得了锁");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("线程名" + thread.getName() + "释放了锁");
            lock.unlock();
        }
    }

    public static void test2() {
        LockTest lockTest = new LockTest();
        for (int i = 0; i < 10; i++) {
            //线程1
            new Thread(() -> {
                lockTest.method2(Thread.currentThread());
            }, i + "").start();
        }
    }

    //需要参与同步的方法
    private void method2(Thread thread) {

//        尝试获取锁
        boolean b = lock.tryLock();

        //        尝试获取锁时间
//        boolean b = false;
//        try {
//            System.out.println("线程名" + thread.getName() + "尝试获取锁--");
//            b = lock.tryLock(2, TimeUnit.SECONDS);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }

        if (!b) {
            //未获取到锁
            System.out.println("线程名" + thread.getName() + "没有获取到锁,直接返回--");
            return;
        }
        //获取到锁
        try {
            TimeUnit.SECONDS.sleep(2);
            System.out.println("线程名" + thread.getName() + "获得了锁");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("线程名" + thread.getName() + "释放了锁");
            lock.unlock();
        }
    }

    public static void test3() {
        LockTest lockTest = new LockTest();
        //线程1
        Thread t1 = new Thread(() -> {
            try {
                lockTest.method3(Thread.currentThread());
            } catch (InterruptedException e) {
                System.out.println("线程名t1中断-----");
//                e.printStackTrace();
            }
        }, "t1");
        t1.start();
//线程1
        Thread t2 = new Thread(() -> {
            try {
                lockTest.method3(Thread.currentThread());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t2");
        t2.start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("线程名t1执行中断");
        t1.interrupt();
    }

    //需要参与同步的方法
    private void method3(Thread thread) throws InterruptedException {
        lock.lockInterruptibly();
        //获取到锁
        System.out.println("线程名" + thread.getName() + "获得了锁");
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (Exception e) {
//            e.printStackTrace();
        } finally {
            System.out.println("线程名" + thread.getName() + "释放了锁");
            lock.unlock();
        }
    }

}

默认的ReentrantLock是不公平的锁,
在这里插入图片描述
公平锁,公平指的是,谁先尝试获取锁,谁就能获取到锁,不公平的话,就是有可能一个线程最先尝试获取锁,但是一直没有获取到锁,获取锁都是随机的.可以通过构造方法创建公平锁:
在这里插入图片描述
在这里插入图片描述

非公平锁性能高于公平锁性能。首先,在恢复一个被挂起的线程与该线程真正运行之间存在着严重的延迟。而且,非公平锁能更充分的利用cpu的时间片,尽量的减少cpu空闲的状态时间。

ReadWriteLock

读写锁,跟lock接口没啥关系主要实现有ReentrantReadWriteLock
在这里插入图片描述
在这里插入图片描述
demo:

public class ReadWriteLockTest {

    private static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

    private static Integer count = 0;

    public static void main(String[] args) {
        ReadWriteLockTest readWriteLockTest = new ReadWriteLockTest();
        for (int i = 0; i < 100; i++) {
            //从1到10的int型随数
            int j = (int) (1 + Math.random() * (10 - 1 + 1));
            if (j % 4 != 1) {
                //写操作
                new Thread("" + i) {
                    public void run() {
                        readWriteLockTest.get(Thread.currentThread());
                    }
                }.start();
            } else {
                //读操作
                int co = i;
                new Thread("" + i) {
                    public void run() {
                        readWriteLockTest.write(Thread.currentThread(), co);
                    }
                }.start();
            }
        }

    }

    public static void get(Thread thread) {
        rwl.readLock().lock();
        try {
            System.out.println("线程" + thread.getName() + "开始读操作...");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程" + thread.getName() + "读操作完毕..." + count);
        } finally {
            rwl.readLock().unlock();
        }
    }

    public static void write(Thread thread, int i) {
        rwl.writeLock().lock();
        try {
            System.out.println("线程" + thread.getName() + "开始写操作---------"+i);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            count = i;
            System.out.println("线程" + thread.getName() + "开始写操作完成------"+i);
        } finally {
            rwl.writeLock().unlock();
        }
    }


}

执行结果:
在这里插入图片描述
开始读操作,线程可以都进行读操作,要是有写操作,会等读操作都完成.

Lock和synchronized的选择
总的来说,Lock和synchronized有以下几点不同:
(1) Lock是一个接口,是JDK层面的实现;而synchronized是Java中的关键字,是Java的内置特性,是JVM层面的实现;

(2) synchronized 在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;

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

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

(5) Lock可以提高多个线程进行读操作的效率。

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

posted @ 2019-04-06 18:05  你就像甜甜的益达  阅读(108)  评论(0编辑  收藏  举报