1,重入:可以反复多次进入,但是只能再同一个线程(最近一次拥有的锁)内,API介绍:ReentrantLock将由最近成功获得锁,并且还没有释放该锁的线程所拥有,当锁没有被另一个线程所拥有,调用lock的线程将成功获取该锁。
2,重入锁可中断:ReentrantLock提供了另外一种可能,就是线程可以中断,就是线程在等待锁的过程中可以中断,而Synchronized不能中断,只能要么执行要么等待
3,公平锁:线程必须按照先后顺序来获得锁,效率低。非公平锁:可以抢锁,效率高,ReentrantLock有构造函数来设置是采用公平锁还是非公平锁,默认是非公平锁。
4,有时间的等待锁:可以指定等待时间,如果超过了时间久不等待。
首先他们都有相同的功能和内存语义
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