• 【Java并发编程九】同步控制


    ReentrantLock(重入锁)

    ReentrantLock的基本使用

     ReentrantLock可以自己决定加锁的位置和解锁的位置。

    package myTest;
    
    import java.util.ArrayList;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class myTest implements Runnable{
        // 重入锁
        public static ReentrantLock lock = new ReentrantLock();
    
        public static int i;
    
        public static void main(String[] args) throws InterruptedException {
            Thread t1 = new Thread(new myTest(), "Thread1");
            Thread t2 = new Thread(new myTest(), "Thread2");
            t1.start();
            t2.start();
            t1.join();
            t2.join();
            System.out.println(i);
        }
    
        @Override
        public void run() {
            lock.lock();
            for (int j = 0; j < 10000; j++) {
                lock.lock();
                try {
                    i ++;
                } finally {
                    lock.unlock();
                }
            }
            lock.unlock();
            System.out.println(Thread.currentThread().getName());
        }
    }
    /**
    Thread1
    Thread2
    20000
    输出的结果总是上述形式。这是因为Thread1有一个锁是执行完所有循环才会释放。
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    ReentrantLock.lockInterruptibly() 可中断锁

     如下面代码所示,如果使用ReentrantLock的lock()方法,则会造成死锁。但是使用了lockInterruptibly可中断锁之后,t2在等待2s之后请求另外一个锁没有得到之后,就会不再尝试去获取这个锁,设置中断标志,直接断开。

    import java.util.ArrayList;
    import java.util.concurrent.locks.ReentrantLock;
    public class myTest implements Runnable{
        // 重入锁
        public static ReentrantLock lock1 = new ReentrantLock();
        public static ReentrantLock lock2 = new ReentrantLock();
        int lock;
        public myTest(int lock) {
            this.lock = lock;
        }
        public static void main(String[] args) throws InterruptedException {
            Thread t1 = new Thread(new myTest(1),"Thread1");
            Thread t2 = new Thread(new myTest(2),"Thread2");
            t1.start();
            t2.start();
            Thread.sleep(2000);
            t2.interrupt();
        }
        @Override
        public void run() {
            try {
                if(lock == 1) {
                    lock1.lockInterruptibly();                System.out.println(Thread.currentThread().getName()+"开始运行");
                    Thread.sleep(500);
                    lock2.lockInterruptibly();
                } else {
                    lock2.lockInterruptibly();                System.out.println(Thread.currentThread().getName()+"开始运行");
                    Thread.sleep(500);
                    lock1.lockInterruptibly();
                }
            } catch (InterruptedException e) {                System.out.println(Thread.currentThread().getName()+"运行出错!");
    //                throw new RuntimeException(e);
            } finally {
                if(lock1.isHeldByCurrentThread()) {
                    lock1.unlock();
                }
                if (lock2.isHeldByCurrentThread()) {
                    lock2.unlock();
                }            System.out.println(Thread.currentThread().getName()+"退出");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    ReentrantLock.tryLock() 限时等待锁

     使用中断锁虽然可以解决死锁,但是很出现数据不一致的问题。可以使用tryLock() 去等待锁,如果时间到了还没有获得锁,便直接放弃。
     如下面代码所示,执行慢的线程,在等待5s后,会直接执行else里面的代码。

    import java.util.ArrayList;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class myTest implements Runnable{
        // 重入锁
        public static ReentrantLock lock = new ReentrantLock();
    
        public static void main(String[] args) throws InterruptedException {
            Thread t1 = new Thread(new myTest(),"Thread1");
            Thread t2 = new Thread(new myTest(),"Thread2");
            t1.start();
            t2.start();
        }
        @Override
        public void run() {
            try {
                if(lock.tryLock(2, TimeUnit.SECONDS)) {
                    Thread.sleep(3000);
                } else {
                    System.out.println(Thread.currentThread().getName()+"得到锁失败");
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                if(lock.isHeldByCurrentThread()) {
                    System.out.println(Thread.currentThread().getName()+"解锁");
                    lock.unlock();
                }
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    公平锁和非公平锁

     ReentrantLock() 默认是非公平锁,默认值为false,两个线程不会公平的获得锁。
     ReentrantLock(true) 为公平锁,两个线程会公平地获取锁,如下面代码所示,两个线程会依次执行。

    import java.util.ArrayList;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.ReentrantLock;
    public class myTest implements Runnable{
        // 重入锁
        public static ReentrantLock lock = new ReentrantLock(true);
    
        public static void main(String[] args) throws InterruptedException {
            Thread t1 = new Thread(new myTest(),"Thread1");
            Thread t2 = new Thread(new myTest(),"Thread2");
            t1.start();
            t2.start();
        }
        @Override
        public void run() {
            while(true) {
                try {
                    lock.lock();
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName()+"获得锁");
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } finally {
                    lock.unlock();
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
  • 相关阅读:
    C++:类与面向对象&static和this关键字&其他关键字
    在TPT中创建SOTIF场景
    Java实现B树
    社招前端经典手写面试题合集
    opencv从入门到精通 哦吼01
    Linux磁盘分区快速上手(讲解详细)
    Spring web security
    CSS 样式优先级
    制作一个简单HTML个人网页网页——人物介绍梵高(HTML+CSS)
    基于scikit-learn支持向量机(Support vector machine)的实现
  • 原文地址:https://blog.csdn.net/qq_45722630/article/details/134518406