本文参考自大佬 公众号:路人甲java
添加链接描述
synchronized 的局限性
synchronized是java内置的关键字,它提供了一种独占的加锁方式。synchronized的获取和释放锁由jvm实现,用户不需要显示的释放锁
如果当前线程获取不到锁,那么会一直阻塞,其他线程也需要一直等待锁的释放。除非当前线程执行完成,或者结束阻塞,或者抛出异常,才能释放锁,别的线程才可以继续争取锁
ReentrantLock是Lock的默认实现,在聊ReentranLock之前,我们需要先弄清楚一些概念:
可重入锁:可重入锁是指同一个线程可以多次获得同一把锁;ReentrantLock和关键字Synchronized都是可重入锁
可中断锁:可中断锁时只线程在获取锁的过程中,是否可以相应线程中断操作。synchronized是不可中断的,ReentrantLock是可中断的
公平锁和非公平锁:公平锁是指多个线程尝试获取同一把锁的时候,获取锁的顺序按照线程到达的先后顺序获取,而不是随机插队的方式获取。synchronized是非公平锁,而ReentrantLock是两种都可以实现,不过默认是非公平锁
t
ReentrantLock的基本使用(上锁,保证数据安全)
package juc;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author yanjun.liu
* @date 2020/6/29--19:31
*/
public class MyReentrantLock {
private static ReentrantLock lock=new ReentrantLock();
private static Integer num=0;
public static void add(){
//对于共享变量的操作,需要保证原子性,上锁
lock.lock();
try {
for(int i=0;i<100000;i++){
num++;
}
}finally {
//解锁
lock.unlock();
}
}
public static class T extends Thread{
@Override
public void run(){
add();
}
}
public static void main(String[] args) throws Exception{
T t = new T();
T t2 = new T();
T t3 = new T();
t.start();
t2.start();
t3.start();
//main线程进行等待三条线程执行完成,在执行
t.join();
t2.join();
t3.join();
System.out.println(num);
}
}
ReentrantLock的使用过程
创建锁对象 private static ReentrantLock lock=new ReentrantLock();
上锁 lock.lock()
解锁 lock.unlock() 解锁一定要放在finally中,否则发生异常无法释放锁,永久阻塞。。。。。
可重入锁,同一个线程可以多次获取同一把锁,获几次,解几次
改造上面的代码,加锁两次
package juc;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author yanjun.liu
* @date 2020/6/29--19:31
*/
public class MyReentrantLock {
private static ReentrantLock lock=new ReentrantLock();
private static Integer num=0;
public static void add(){
//对于共享变量的操作,需要保证原子性,上锁
lock.lock();
lock.lock();
try {
for(int i=0;i<100000;i++){
num++;
}
}finally {
//解锁
lock.unlock();
lock.unlock();
}
}
public static class T extends Thread{
@Override
public void run(){
add();
}
}
public static void main(String[] args) throws Exception{
T t = new T();
T t2 = new T();
T t3 = new T();
t.start();
t2.start();
t3.start();
//main线程进行等待三条线程执行完成,在执行
t.join();
t2.join();
t3.join();
System.out.println(num);
}
}
上锁lock.lock();一定要放在try{}代码块之外,如果在try中上锁,在上锁之前,其他代码抛出异常,那么就会上锁失败,走finally释放锁就会抛出异常,因为压根就没上锁成功
package juc;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author yanjun.liu
* @date 2020/6/29--19:31
*/
public class MyReentrantLock {
private static ReentrantLock lock=new ReentrantLock();
private static Integer num=0;
public static void add(){
try {
//这里会抛出异常,下面上锁代码不会执行
int x=1;
x=1/0;
lock.lock();
lock.lock();
for(int i=0;i<100000;i++){
num++;
}
}finally {
//解锁会抛出异常
lock.unlock();
lock.unlock();
}
}
public static class T extends Thread{
@Override
public void run(){
add();
}
}
public static void main(String[] args) throws Exception{
T t = new T();
T t2 = new T();
T t3 = new T();
t.start();
t2.start();
t3.start();
//main线程进行等待三条线程执行完成,在执行
t.join();
t2.join();
t3.join();
System.out.println(num);
}
}
上述代码将抛出IllegalMonitorStateException异常
抛出该异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器,然而本身没有指定的监视器的线程。
Exception in thread "Thread-0" Exception in thread "Thread-1" Exception in thread "Thread-2" java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
at juc.MyReentrantLock.add(MyReentrantLock.java:26)
at juc.MyReentrantLock$T.run(MyReentrantLock.java:35)
java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
at juc.MyReentrantLock.add(MyReentrantLock.java:26)
at juc.MyReentrantLock$T.run(MyReentrantLock.java:35)
java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
at juc.MyReentrantLock.add(MyReentrantLock.java:26)
at juc.MyReentrantLock$T.run(MyReentrantLock.java:35)
0