java 并发编程 ReentrantLock

本文参考自大佬 公众号:路人甲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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章