• 【多线程 - 09、线程同步 Lock】


    重入锁实现线程同步

    在JDK1.5中新增了一个java.util.concurrent包来支持同步。

    使用JUC里的Lock与使用synchronized方法和块具有相同的基本行为和语义,并且扩展了其能力

    关键字synchronized实现的同步的锁,是隐藏的,所以并不明确是在哪里加上了锁,在哪里释放了锁。为了更明确的控制从哪里开始锁,在哪里释放锁,JDK1.5提供了Lock

    Lock是一个接口,真正用的是它的实现类ReentrantLock。

    ReenreantLock类的常用方法

    • ReentrantLock() : 创建一个ReentrantLock实例 ,传入参数true可以获得公平锁,但由于能大幅度降低程序运行效率,不推荐使用
    • lock() : 获得锁
    • unlock() : 释放锁

    例子:四个线程卖100张票

    public class ThreadTest {
        public static void main(String[] args) {
            synchronizeThread st = new synchronizeThread();
            new Thread(st, "1").start();
            new Thread(st, "2").start();
            new Thread(st, "3").start();
            new Thread(st, "4").start();
        }
    }
    
    class synchronizeThread implements Runnable {
        private Integer ticketNumber = 100;
        private Lock lock = new ReentrantLock();//创建一个重入锁对象
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                lock.lock();//开启锁
               try {
                   if (ticketNumber > 0) {
                       System.out.println("线程【" + Thread.currentThread().getName() + "】卖出了一张票,现在剩余了【" + ticketNumber + "】张票");
                       ticketNumber--;
                   } else {
                       break;
                   }
               }catch (Exception e){
                   e.printStackTrace();
               }finally {//注意:要放到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
    • 29
    • 30
    • 31
    • 32

    Lock对象和synchronized关键字的选择

    在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。

    同步锁的释放问题的总结

    用关键字synchronized构成同步代码块和同步方法,来实现多线程的同步,本质上可以理解为底层的程序给线程加了一把看不见的隐藏的锁,只有获取到这把锁的线程才能被执行,没拿到的线程就得等着,从而控制线程的执行顺序,达到同步效果,所以,任何线程进入同步代码块、同步方法之前,必须先获得对于同步监测器的锁定,那么谁释放对同步监测器的锁定呢?

    在Java中,程序无法显式的释放对同步监测器的锁定,释放权在底层的JVM上,JVM会从释放机制中自动的释放。

    下面情况下会进行同步监测器锁定的释放

    • 当前线程的同步方法、同步代码块执行正常结束,当前线程即释放随同步监测器的锁定;
    • 当前线程的同步方法、同步代码块中遇到break、return终止了该代码块、方法的继续执行,当前线程会释放同步监测器的锁定;
    • 当前线程在同步方法、同步代码块中出现了未处理的error或者exception,导致了该代码块、该方法异常结束时,当前线程会释放同步监测器的锁定;
    • 当前线程执行同步代码块或同步方法时,程序调用了同步监测器的wait()方法,当前线程暂停,则当前线程会释放同步监测器的锁定。

    下面情况下不会进行同步监测器锁定的释放

    • 线程执行同步代码块或者同步方法时,程序调用了Thread.sleep()、Thread.yield()方法来暂停当前线程执行,当前线程不会释放对同步监测器的锁定;
    • 线程执行同步代码块时,其他线程调用了该线程的suspend()方法(suspend会阻塞线程直到另一个线程调用resume,这个方法容易死锁,已经不推荐使用了,了解一下就ok)将该线程挂起,也不会释放同步监测器的锁定。
  • 相关阅读:
    Pikachu靶场——SSRF 服务端请求伪造
    工程电磁场复习基本知识点
    蓝牙5.0对比4.2的主要优势
    【运维 Pro】时序场景实践与原理 - 1. 分布与分区
    案例复现,带你分析Priority Blocking Queue比较器异常导致的NPE问题
    数据库实验三 数据查询一
    【开源教程2】疯壳·开源编队无人机-硬件资源简介
    华为云云耀云服务器L实例评测|了解配置和管理L型云服务器
    基于R语言piecewiseSEM结构方程模型在生态环境领域实践技术
    第13章_瑞萨MCU零基础入门系列教程之Common SPI
  • 原文地址:https://blog.csdn.net/qq_46023503/article/details/134340569