zoukankan      html  css  js  c++  java
  • 多线程高并发编程(2) -- 可重入锁介绍和自定义

    背景:

      什么是 “可重入”?可重入就是说某个线程已经获得某个锁,可以再次获取锁而不会出现死锁。即可重入锁的作用就是为了避免死锁,java中synchronized和ReentrantLock都是可重入锁。

      //synchronized 可重入锁
        private void test() {
            //  第一次获得锁
            synchronized (this) {
                while (true) {
                    //  第二次获得同样的锁
                    synchronized (this) {
                        System.out.println("ReentrantLock!");
                    }
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
      //ReentrantLock可重入锁
        Lock lock = new ReentrantLock();
        private void test1() {
            lock.lock();
            try {
                test2();
            } finally {
                lock.unlock();
            }
        }
        private void test2() {
            lock.lock();
            try {
                System.out.println("ReentrantLock!");
            } finally {
                lock.unlock();
            }
        }

    一.自定义不可重入锁

      所谓不可重入锁,即若当前线程执行某个方法已经获取了该锁,那么在方法中尝试再次获取锁时,就会获取不到被阻塞。下面的线程执行test1()方法首先获取lock,接下来执行test2()方法就无法执行test2()中的逻辑,必须先释放锁。

    // 不可重入锁
    class Lock {
        //是否占用
        private boolean isLocked = false;
    
        //使用锁
        public synchronized void lock() {
            while (isLocked) {//已经占用
                try {
                    this.wait();//等待
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            isLocked = true;//修改标识为已经占用
        }
    
        //释放锁
        public synchronized void unLock() {
            isLocked = false;//修改标识为未占用
            notify();//唤醒等待线程
        }
    
    }
    ============使用===========
        Lock lock = new Lock();
    
        public void test1() {
            lock.lock();
            test2();
            lock.unLock();
        }
    
        private void test2() {
            lock.lock();
            //...
            lock.unLock();
        }

    二.自定义可重入锁

       流程:

    1. 定义锁占用标识、存储线程、线程锁持有数量;
    2. 使用锁:判断是否已经占用和当前线程是否不等于存储线程,如果条件符合进入等待,不符合则修改占用标识、存储线程为当前线程、线程锁数量+1;
    3. 释放锁:判断当前线程是否等于存储线程,条件符合则线程锁数量-1,当线程锁数量=0时,修改占用标识,唤醒等待线程,将存储线程置为null;
    // 可重入锁
    class ReLock{
        //是否占用
        private boolean isLocked = false;
        private Thread lockedBy = null; //存储线程
        private int holdCount = 0;
        //使用锁
        public synchronized void lock() throws InterruptedException {
            Thread t = Thread.currentThread();
            while(isLocked && lockedBy != t) {
                wait();
            }
            isLocked = true;
            lockedBy = t;
            holdCount ++;
        }
        //释放锁
        public synchronized void unlock() {
            if(Thread.currentThread() == lockedBy) {
                holdCount --;
                if(holdCount ==0) {
                    isLocked = false;
                    notify();
                    lockedBy = null;
                }        
            }        
        }
        public int getHoldCount() {
            return holdCount;
        }
    }
    ==============使用===============
    public class LockTest {
        ReLock lock = new ReLock();
        public void test1() throws InterruptedException {
            lock.lock();
            System.out.println(lock.getHoldCount());
            test2();
            lock.unlock();
            System.out.println(lock.getHoldCount());
        }
        //可重入
        public void test2() throws InterruptedException {
            lock.lock();
            System.out.println(lock.getHoldCount());
            //...................
            lock.unlock();
            System.out.println(lock.getHoldCount());
        }
        public static void main(String[] args) throws InterruptedException {
            LockTest lockTest= new LockTest();
            lockTest.test1();            
            Thread.sleep(1000);        
            System.out.println(lockTest.lock.getHoldCount());
        }
    
    }
  • 相关阅读:
    二叉树的递归遍历 The Falling Leaves UVa 699
    二叉树的递归遍历 天平UVa839
    二叉树的递归遍历 Tree UVa548
    通过缓冲传递数据-结构体
    fread读取文件(二进制文件)
    socket编程--相关函数--sendto();read();
    socket 编程--sockaddr与sockaddr_in区别与联系(转)
    百度Apollo 尝试
    检测服务器端口是否被占用
    qt5的.ui文件在VS2010中无法编译问题
  • 原文地址:https://www.cnblogs.com/huangrenhui/p/12711778.html
Copyright © 2011-2022 走看看