java并发(4):可重入锁ReentrantLock

概念理解:

1,重入:可以反复多次进入,但是只能再同一个线程(最近一次拥有的锁)内,API介绍:ReentrantLock将由最近成功获得锁,并且还没有释放该锁的线程所拥有,当锁没有被另一个线程所拥有,调用lock的线程将成功获取该锁。

2,重入锁可中断:ReentrantLock提供了另外一种可能,就是线程可以中断,就是线程在等待锁的过程中可以中断,而Synchronized不能中断,只能要么执行要么等待

3,公平锁:线程必须按照先后顺序来获得锁,效率低。非公平锁:可以抢锁,效率高,ReentrantLock有构造函数来设置是采用公平锁还是非公平锁,默认是非公平锁。

4,有时间的等待锁:可以指定等待时间,如果超过了时间久不等待。

ReentrantLock与Synchronized区别:

首先他们都有相同的功能和内存语义

1,与synchronized相比,reentrantLock提供了更多,更全面的功能,具备更强的扩展性

2,ReentrantLock提供了条件Condition,对线程的等待,唤醒操作更加详细和灵活,所以在多个条件变量和高度竞争锁的地方,ReentrantLock更加适合

3,reentrantLock提供了可轮询的锁清秋,他会尝试这取获取锁,如果成功就继续,否则可以等到下次运行时处理,而synchronized则一旦进入锁请求要么成功要么阻塞,所以reentrantLock更不容易死锁。

4,reentrantLock支持更加灵活的同步代码块,但是synchronized,只能在同一个synchronized块结构中获取和释放,lock只要在finally中释放,并且是一定要释放。

5,reentrantLock支持中断。

代码演示:

1,lock的用法:

package com.study.webapp.lock;

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockTest implements Runnable {

    private static ReentrantLock lock = new ReentrantLock();

    private static int i = 0;

    @Override
    public void run() {

        for (int j = 0; j < 1000; j++) {
            try {
                // 需要用就添加,更加灵活
                lock.lock();
                i++;
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 不过一定要手动释放锁
                lock.unlock();
            }
        }

    }

    public static void main(String[] args) throws Exception {
        ReentrantLockTest t = new ReentrantLockTest();
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(i);
    }

}
 

2,中断演示:

package com.study.webapp.lock;

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockInterrupt implements Runnable {
    private static ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        try {
            // 申请锁,这是可以进中断申请的申请锁操作
            lock.lockInterruptibly();
            // 睡眠20秒,在结束之前,main方法中要中断t2的获取锁操作
            Thread.sleep(20000);
        } catch (Exception e) {
            // TODO: handle exception
        } finally {
            String threadName = Thread.currentThread().getName();
            // 中断后跑出异常,最后释放锁
            // 如果t1就释放,因为t2没有拿到锁,所以不用释放
            if ("Tread-1".equals(threadName)) {
                lock.unlock();
            }
            System.out.println(threadName + ":停止");

        }
    }

    public static void main(String[] args) {
        ReentrantLockInterrupt in = new ReentrantLockInterrupt();
        Thread t1 = new Thread(in, "Thread-1");
        Thread t2 = new Thread(in, "Thread-2");
        t1.start();
        try {
            // 让主线程停一下,先让t1获得锁再启动t2
            Thread.sleep(1000);
        } catch (Exception e) {
            // TODO: handle exception
        }
        t2.start();
        t2.interrupt();
        /**
         * 过程是t1拿到锁然后睡眠20秒,然后开始t2线程,t2线程没有拿到锁就可以直接中断停止,然后t1醒来,释放锁
         */
    }

}
 

3,等待时间锁演示

package com.study.webapp.lock;

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

public class TimeLock implements Runnable {

    private static ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        try {
            // 获取锁成功则返回true
            // tryLock方法,设置获取3次失败就放弃获取,第一个获取锁就睡眠5秒,第二个线程就获取不到锁被迫停止
            // 如果tryLock()方法不传入任何参数,那么获取锁的线程不会等待锁,则立即返回false。
            if (lock.tryLock(3, TimeUnit.SECONDS)) {
                Thread.sleep(5000);
            } else {
                System.out.println(Thread.currentThread().getName() + "获取锁失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 如果当前线程持有锁,则释放锁。
            if (lock.isHeldByCurrentThread()) {
                System.out.println(Thread.currentThread().getName() + "释放锁了");
                lock.unlock();
            }
        }

    }

    public static void main(String[] args) {
        TimeLock t = new TimeLock();
        Thread t1 = new Thread(t, "thread-1");
        Thread t2 = new Thread(t, "thread-2");
        t1.start();
        t2.start();
    }

}
 

4,公平锁与非公平锁

package com.study.webapp.lock;

import java.util.concurrent.locks.ReentrantLock;

/**
 * 公平锁与非公平锁
 * 
 * @author admin
 *
 *         2018年12月19日
 */
public class failrLock {
    // 填true表示是公平锁,false非公平,默认false可不填,
    private static ReentrantLock lock = new ReentrantLock(true);

    private static Runnable runnable = () -> {
        for (int i = 0; i < 10000; i++) {
            try {
                lock.lock();
                System.out.println(Thread.currentThread().getName());
            } finally {
                lock.unlock();
            }
        }
    };

    public static void main(String[] args) {
        Thread t1 = new Thread(runnable, "t--1");
        Thread t2 = new Thread(runnable, "t--2");
        Thread t3 = new Thread(runnable, "t--3");
        t1.start();
        t2.start();
        t3.start();
    }

}

还没学够,后续再深入

学习:http://cmsblogs.com/?p=2210

         https://blog.csdn.net/jiangbr/article/details/79337547

         https://blog.csdn.net/i_am_kop/article/details/80958856

你可能感兴趣的:(java并发编程)