iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Java多线程中Lock的使用小结
  • 569
分享到

Java多线程中Lock的使用小结

Java多线程LockJavaLock 2023-05-18 08:05:33 569人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

jdk1.5 以后,在 java.util.concurrent.locks 包下,有一组实现线程同步的接口和类,说到线程的同步,可能大家都会想到 synchronized 关键字,

jdk1.5 以后,在 java.util.concurrent.locks 包下,有一组实现线程同步的接口和类,说到线程的同步,可能大家都会想到 synchronized 关键字,

这是 java 内置的关键字,用来处理线程同步的,但这个关键字有很多的缺陷,使用起来也不是很方便和直观,所以就出现了 Lock,下面,我们

就来对比着讲解 Lock。

通常我们在使用 synchronized 关键字的时候会遇到下面这些问题:

(1)不可控性,无法做到随心的加和释放锁。

(2)效率比较低下,比如我们现在并发的读两个文件,读与读之间是互不影响的,但如果给这个读的对象使用 synchronized 来实现同步的话,

那么只要有一个线程进入了,那么其他的线程都要等待。

(3)无法知道线程是否获取到了锁。

而上面 synchronized 的这些问题,Lock 都可以很好的解决,并且 jdk1.5 以后,还提供了各种锁,例如读写锁,但有一点需要注意,使用 synchronized

关键时,无须手动释放锁,但使用 Lock 必须手动释放锁。下面我们就来学习一下 Lock 锁。

Lock 是一个上层的接口,其原型如下,总共提供了 6 个方法:

public interface Lock {
  // 用来获取锁,如果锁已经被其他线程获取,则一直等待,直到获取到锁
   void lock();
  // 该方法获取锁时,可以响应中断,比如现在有两个线程,一个已经获取到了锁,另一个线程调用这个方法正在等待锁,但是此刻又不想让这个线程一直在这死等,可以通过
    调用线程的Thread.interrupted()方法,来中断线程的等待过程
  void lockInterruptibly() throws InterruptedException;
  // tryLock方法会返回bool值,该方法会尝试着获取锁,如果获取到锁,就返回true,如果没有获取到锁,就返回false,但是该方法会立刻返回,而不会一直等待
   boolean tryLock();
  // 这个方法和上面的tryLock差不多是一样的,只是会尝试指定的时间,如果在指定的时间内拿到了锁,则会返回true,如果在指定的时间内没有拿到锁,则会返回false
   boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
  // 释放锁
   void unlock();
  // 实现线程通信,相当于wait和notify,后面会单独讲解
   Condition newCondition();
}

那么这几个方法该如何使用了?前面我们说到,使用 Lock 是需要手动释放锁的,但是如果程序中抛出了异常,那么就无法做到释放锁,有可能引起死锁,

所以我们在使用 Lock 的时候,有一种固定的格式,如下:

Lock l = ...;
      l.lock();
      try {
        // access the resource protected by this lock
      } finally {// 必须使用try,最后在finally里面释放锁
        l.unlock();
      }

下面我们来看一个简单的例子,代码如下:


public class LockDemo {
    // new一个锁对象,注意此处必须声明成类对象,保持只有一把锁,ReentrantLock是Lock的唯一实现类
   Lock lock = new ReentrantLock();
   public void readFile(String fileMessage){
      lock.lock();// 上锁
      try{
         System.out.println(Thread.currentThread().getName()+"得到了锁,正在读取文件……");
         for(int i=0; i<fileMessage.length(); i++){
            System.out.print(fileMessage.charAt(i));
         }
         System.out.println();
         System.out.println("文件读取完毕!");
      }finally{
         System.out.println(Thread.currentThread().getName()+"释放了锁!");
         lock.unlock();
      }
   }
   public void demo(final String fileMessage){
      // 创建若干个线程
      ExecutorService service = Executors.newCachedThreadPool();
      // 提交20个任务
      for(int i=0; i<20; i++){
         service.execute(new Runnable() {
            @Override
            public void run() {
               readFile(fileMessage);
               try {
                  Thread.sleep(20);
               } catch (InterruptedException e) {
                  e.printStackTrace();
               }
            }
         });
      }
    // 释放线程池中的线程
      service.shutdown();
   }
}

Lock与synchronized的对比

1、作用

lock 和 synchronized 都是 Java 中去用来解决线程安全问题的一个工具

2、来源

sychronized 是 Java 中的一个关键字。

lock 是 JUC 包里面提供的一个接口,这个接口有很多实现类,其中就包括我们最常用的 ReentrantLock(可重入锁)。

3、锁的力度

sychronized 可以通过两种方式去控制锁的力度:

把 sychronized 关键字修饰在方法层面。
修饰在代码块上。
锁对象的不同:

锁对象为静态对象或者是class对象,那这个锁属于全局锁。
锁对象为普通实例对象,那这个锁的范围取决于这个实例的生命周期。
lock锁的力度是通过 lock()与unlock()两个方法决定的。在两个方法之间的代码能保证其线程安全。lock的作用域取决于lock实例的生命周期。

4、灵活性

lock锁比sychronized的灵活性更高。

lock可以自主的去决定什么时候加锁与释放锁。只需要调用lock 的lock()和unlock()这两个方法就可以。

sychronized 由于是一个关键字,所以他无法实现非阻塞竞争锁的方法,一个线程获取锁之后,其他锁只能等待那个线程释放之后才能有获取锁的机会。

5、公平锁与非公平锁

公平锁:多个线程按照申请锁的顺序去获得锁,线程会直接进入队列去排队,永远都是队列的第一位才能得到锁。

优点:所有的线程都能得到资源,不会饿死。
缺点:吞吐量低,队列里面除了第一个线程,其他的线程都会阻塞,cpu唤醒阻塞线程的开销大。
非公平锁:多个线程去获取锁的时候,会直接去尝试获取,获取不到,再去进入等待队列,如果能获取到,就直接获取到锁。

优点:可以减少CPU唤醒线程的开销,整体的吞吐效率会高点,CPU也不必取唤醒所有线程,会减少唤起线程的数量。
缺点:可能导致队列中间的线程一直获取不到锁或者长时间获取不到锁,最终饿死。
lock提供了公平锁和非公平锁两种机制(默认非公平锁)。

sychronized是非公平锁。

6、异常是否释放锁

synchronized锁的释放是被动的,当sychronized同步代码块执行结束或者出现异常的时候才会被释放。

lock锁发生异常的时候,不会主动释放占有的锁,必须手动unlock()来释放,所以我们一般都是将同步代码块放进try-catch里面,finally中写入unlock()方法,避免死锁发生。

7、判断是否能获取锁

synchronized不能。

lock提供了非阻塞竞争锁的方法trylock(),返回值是Boolean类型。它表示的是用来尝试获取锁:成功获取则返回true;获取失败则返回false,这个方法无论如何都会立即返回。

8、调度方式

synchronized使用的是object对象本身的wait、notify、notifyAll方法,而lock使用的是Condition进行线程之间的调度。

9、是否能中断

synchronized只能等待锁的释放,不能响应中断。

lock等待锁过程中可以用interrupt()来中断。

10、性能

如果竞争不激烈,性能差不多;竞争激烈时,lock的性能会更好。

lock锁还能使用readwritelock实现读写分离,提高多线程的读操作效率。

11、sychronized锁升级

synchronized 代码块是由一对 monitorenter/monitorexit 指令实现的。Monitor的实现完全是依靠操作系统内部的互斥锁,因为需要进行用户态到内核态的切换,所以同步操作是一个无差别的重量级操作。

所以现在JVM提供了三种不同的锁:偏向锁、轻量级锁、重量级锁。

偏向锁:
当没有竞争出现时,默认使用偏向锁。线程会利用 CAS 操作在对象头上设置线程 ID ,以表示对象偏向当前线程。

目的:在很多应用场景中,大部分对象生命周期最多会被一个线程锁定,使用偏向锁可以降低无竞争时的开销。

轻量级锁:
JVM比较当前线程的 threadID 和 Java 对象头中的threadID是否一致,如果不一致(比如线程2要竞争锁对象),那么需要查看 Java 对象头中记录的线程1是否存活(偏向锁不会主动释放因此还是存储的线程1的 threadID),如果没有存活,那么锁对象还是为偏向锁(对象头中的threadID为线程2的);如果存活,那么撤销偏向锁,升级为轻量级锁。

当有其他线程想访问加了轻量级锁的资源时,会使用自旋锁优化,来进行资源访问。

目的:竞争锁对象的线程不多,而且线程持有锁的时间也不长的情景。因为阻塞线程需要CPU从用户态转到内核态,开销大,如果刚刚阻塞不久这个锁就被释放了,就得不偿失了,因此这个时候就干脆不阻塞这个线程,让它自旋这等待锁释放。

重量级锁:
自旋失败,很大概率 再一次自选也是失败,因此直接升级成重量级锁,进行线程阻塞,减少cpu消耗。

当锁升级为重量级锁后,未抢到锁的线程都会被阻塞,进入阻塞队列。

到此这篇关于Java多线程中Lock的使用小结的文章就介绍到这了,更多相关Java多线程Lock内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Java多线程中Lock的使用小结

本文链接: https://www.lsjlt.com/news/211887.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java多线程中Lock的使用小结
    Jdk1.5 以后,在 java.util.concurrent.locks 包下,有一组实现线程同步的接口和类,说到线程的同步,可能大家都会想到 synchronized 关键字,...
    99+
    2023-05-18
    Java多线程Lock Java Lock
  • Java多线程中Lock锁的使用小结
    Lock基本使用 Lock它是java.util.concurrent.locks下的一个接口,它也是用来处理线程同步问题的。 public interface Lock { ...
    99+
    2024-04-02
  • Java多线程中Lock锁如何使用
    这篇文章主要介绍“Java多线程中Lock锁如何使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java多线程中Lock锁如何使用”文章能帮助大家解决问题。Lock基本使用Lock它是java.u...
    99+
    2023-07-02
  • C#如何使用多线程中的lock
    小编给大家分享一下C#如何使用多线程中的lock,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!经常碰到同时需要对某个数据进行操作,或者对某个文件进行读写操作,对于...
    99+
    2023-06-17
  • python中的多线程锁lock=threading.Lock()使用方式
    目录多线程锁lock=threading.Lock()使用疑问解决方法例子python多线程中锁的概念锁可以独立提取出来概念线程不安全线程锁多线程锁lock=threading.Lo...
    99+
    2024-04-02
  • python中的多线程锁lock=threading.Lock()如何使用
    这篇文章主要介绍“python中的多线程锁lock=threading.Lock()如何使用”,在日常操作中,相信很多人在python中的多线程锁lock=threading.Lock()如何使用问题上存在疑惑,小编查阅了各式资料,整理出简...
    99+
    2023-07-02
  • C#多线程中lock怎么用
    这篇文章主要介绍了C#多线程中lock怎么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。下面就是一段简单的代码。public class AccessC...
    99+
    2023-06-17
  • Java多线程的具体介绍与使用笔记小结
    目录一、基本概念:线程、进程1.1、进程与线程的具体介绍1.2、对于CPU而言的理解1.3、为什么要使用多线程二、线程的创建与使用2.1、如何去创建和启动一个线程2.2、Thread...
    99+
    2024-04-02
  • java线程池ThreadPoolExecutor类使用小结
    目录一、workQueue任务队列二、拒绝策略三、ThreadFactory自定义线程创建四、ThreadPoolExecutor扩展五、线程池线程数量在《阿里巴巴java开发手册》...
    99+
    2024-04-02
  • Java多线程之同步锁-lock详解
    目录一、题目描述二、解题思路三、代码详解一、题目描述 题目: 同步锁出现的目的就是为了解决多线程安全问题。 同步锁的几种方式 synchronized 1、同步代码块 2、同步方法 ...
    99+
    2024-04-02
  • Qt 中开启线程的多种方式小结
    目录简介1. 继承 QThread 重写 run 函数2. 继承 QObject 调用 moveToThread3. 继承 QRunnable 重新 run 函数,结合 QThrea...
    99+
    2024-04-02
  • Python线程锁Lock的使用介绍
    这篇文章主要讲解了“Python线程锁Lock的使用介绍”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python线程锁Lock的使用介绍”吧!我们知道Python的线程是封装了底层操作系统...
    99+
    2023-06-02
  • C#多线程锁lock和Monitor怎么用
    本文小编为大家详细介绍“C#多线程锁lock和Monitor怎么用”,内容详细,步骤清晰,细节处理妥当,希望这篇“C#多线程锁lock和Monitor怎么用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。1,Loc...
    99+
    2023-06-29
  • java中多线程与线程池的基本使用方法
    目录前言继承Thread 实现Runnale接口Callable线程池常见的4种线程池。总结前言 在java中,如果每个请求到达就创建一个新线程,开销是相当大的。在实际使用中,服务器...
    99+
    2024-04-02
  • java怎么使用多线程解决主线程提前结束问题
    这篇文章主要介绍“java怎么使用多线程解决主线程提前结束问题”,在日常操作中,相信很多人在java怎么使用多线程解决主线程提前结束问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java怎么使用多线程解决...
    99+
    2023-07-05
  • java中lock怎么使用
    在Java中,Lock接口是用于实现锁的机制。以下是Lock接口的使用方法:1. 创建Lock对象:可以使用ReentrantLoc...
    99+
    2023-10-20
    java
  • C#使用LOCK实现线程同步
    一、简介 线程安全概念:线程安全是指在当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。 线程有可能和...
    99+
    2024-04-02
  • Python中多线程总结
    Python中的多线程多线程一个进程中有多个线程就是多线程。一个进程中至少有一个线程,并作为程序的入口,这个就是主线程。一个进程至少有一个主进程,其他线程称为工作线程。线程安全:线程执行一段代码,不会产生不确定的结果,那这段代码就是线程安全...
    99+
    2023-01-31
    多线程 Python
  • Java多线程的常用创建方式总结
    Java多线程的创建方式 Java现在有四种创建的方式:继承Threa类、实现Runnable接口、实现Callable接口、线程池 Thread、Runnable都在java.la...
    99+
    2024-04-02
  • Java 多线程学习总结3
    在上一篇中,我们当然希望a++,b++执行完之后,show方法再来show.我们需要的是“原子”动作,一次性地把a++,b++不间断地执行。在java中是利用“互斥”的方法,互斥谁呢?互斥的是相同对象的加锁代码。如果我们把第一篇的SomeB...
    99+
    2023-01-31
    多线程 Java
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作