首页 > 编程语言 >二、并发编程与多线程-2.1、J.U.C和锁(中篇)

二、并发编程与多线程-2.1、J.U.C和锁(中篇)

时间:2024-09-03 18:25:40浏览次数:18  
标签:中篇 变量 synchronized Lock 死锁 线程 2.1 多线程 共享

2.1、J.U.C和锁(中篇)

2.1.4、什么是CAS?

答:
CAS是Java中Unsafe类里面的方法,全称是CompareAndSwap,是比较并交换的意思。作用就是保证在多线程环境下,对于修改共享变量操作的原子性。

扩展:
CAS保证修改共享变量操作原子性的实现逻辑:
CAS方法里有三个参数,依次分别是共享变量的内存地址偏移量、当前值(原来的值)、新值(期望更改之后的值)。

  1. 当多个线程要修改同一个共享变量时,首先要读取该变量的当前值;
  2. 然后,将要修改的值(共享变量的内存地址偏移量对应的值)与当前值进行比较;
  3. 如果比较结果相等,说明当前值没有被其他线程修改过,可以进行修改操作;
  4. 使用原子操作将新值赋给共享变量;
  5. 如果比较结果不相等,说明当前值已经被其他线程修改过,此时需要重新读取当前值,并重复以上步骤。

CAS保证原子性的关键在于比较和交换操作是原子的,即在执行期间不会被其他线程干扰。说白了,就是保留了共享变量原来的值,更新之前,获取共享变量此时的值,判断是否与原来的值相等,如果相等则表示未被修改,执行更新操作;反之则放弃此次更新,重新获取共享变量当前值重试这些流程。

2.1.5、什么是乐观锁?什么是悲观锁?

答:
乐观锁和悲观锁并不是指具体的某种锁,而是一种思想。

  • 乐观锁就是持乐观态度的锁,乐观锁在操作数据时认为别的线程不会同时修改数据,所以不会上锁,但是在更新数据的时候要判断在此期间数据有没有被别的线程修改过。比如说CAS就使用了乐观锁的思想。应用场景就是乐观锁适用于写少读多的情况,这样能够减少操作冲突,省去了锁竞争的开销,因为线程不需要竞争多资源。
  • 悲观锁就是持悲观态度的锁,每次在操作数据时都认为别的线程也会同时修改数据,所以每次操作数据时都会上锁,这样别的线程想拿到这个数据就会阻塞,知道线程拿到锁。比如说行锁、表锁、读锁、写锁、还有Java API中的synchronized和ReentrantLock等独占锁都是用了悲观锁的思想,操作数据之前先上锁。应用场景就是悲观锁适用于写多读少的情况,因为遇到频繁操作数据的情况如果还使用乐观锁,就会经常出现操作冲突,进而导致应用层不断的重试,反而会降低系统的性能。

扩展:
其实看到这里自然也就明白了,使用并发编程其实就是要解决两个问题,其实也就是使用并发编程的逻辑:
1. 如何使用并发编程提高程序的性能?答案就是多线程的合理使用;
2. 如何解决使用并发编程所带来的并发冲突问题?答案就是锁的合理使用

2.1.6、什么条件下会产生死锁?如何避免死锁?

答:
死锁是指两个或多个线程被永久阻塞,因为每个线程都在等待某个其他线程释放资源,而无法继续执行。这种情况发生在多个线程同时持有一些共享资源,并且每个线程还需要获取其他线程持有的资源。
产生死锁的四个必要条件:

  1. 互斥条件:资源不能被多个线程同时占用
  2. 请求和保持条件:线程持有资源并请求其他线程持有的资源
  3. 不可剥夺条件:线程已经获得的资源不能被其他线程强制性剥夺
  4. 循环等待条件:存在一个循环等待的资源链,每个线程都在等待下一个线程持有的资源

产生死锁后,就只能通过外部干预来解决问题,比如重启程序或者Kill线程;在产生死锁前,可以通过一些方式来避免死锁,上述产生死锁的四个必要条件破环其中一种就行:

  1. 对于互斥条件:这个没法破环,因为互斥条件是互斥锁的基本约束。
  2. 对于请求和保持条件:我们可以在首次执行时一次性申请所有的资源,这样就不存在等待锁的问题了。
  3. 对于不可剥夺条件:占用部分资源的线程在申请其他资源的时候如果申请不到,可以让该线程主动释放已占用的资源。
  4. 对于循环等待条件:可以通过按序申请资源来预防死锁的产生。按序申请就是给资源编号,所有线程都要按照线性化的序号申请共享资源。先申请序号小的,再申请序号大的。

2.1.7、synchronized和Lock的区别是什么?

答:

  1. 特性区别:synchronized是Java内置的一个关键字,而Lock是J.U.C包下的一个接口,它有很多实现类,比如ReentrantLock。
  2. 用法区别:synchronized可以直接在方法上或者代码块中使用;而Lock的使用需要通过Lock实现类的对象调用lock()方法和unlock()方法来获取锁和释放锁的。
示例:
// synchronized控制方法时
public synchronized void syncMethod() {
}
// synchronized控制代码块时
Object lock = new Object();
public void syncMethod() {
    synchronized(lock) {
        // 代码块中的逻辑...
    }
}

// Lock的使用
Lock reentrantLock = new ReentrantLock();
pubilic void syncMethod() {
    reentrantLock.lock(); //添加锁
    // 线程安全的代码...
    reentrantLock.unlock(); //释放锁
}
  1. 可重入性:synchronized是可重入锁,一个线程可以多次获取同一个锁。而Lock可以设置是否可重入,通过设置为不可重入可以避免死锁的发生。
  2. 锁的获取方式:synchronized是隐式获取锁,当线程进入synchronized代码块或方法时,会自动获取锁。而Lock需要显式地调用lock()方法来获取锁,同时还可以设置超时时间。
  3. 锁的释放方式:synchronized会在代码块或方法执行完毕后自动释放锁。而Lock需要显式地调用unlock()方法来释放锁,通常在finally块中使用
  4. 条件变量:Lock提供了条件变量的功能,可以使用Condition对象在特定条件下挂起和唤醒线程。而synchronized没有直接提供条件变量,需要通过wait()、notify()和notifyAll()来实现。

扩展:
synchronized是一种更简单、更方便的线程同步机制,适合大多数情况下的使用。而Lock则提供了更灵活、更强大的线程同步功能,适用于一些需要更精细控制的场景。
无论是synchronized关键字还是Lock锁,目的都是为了保证线程安全:也就是数据的一致性。当被问到多个线程之间如何共享数据并保证数据的一致性,使用synchronized关键字或Lock就是答案

标签:中篇,变量,synchronized,Lock,死锁,线程,2.1,多线程,共享
From: https://blog.csdn.net/weixin_61769871/article/details/141789370

相关文章

  • flask多线程下数据库操作(简单示例)
    前言背景:开了两个线程操作数据库插入但是获取不到db的信息,自己摸索的方法不一定是最佳的,有更好的可以评论或私信,感谢大佬话不多说,直接上代码 #模型里面的多线程新增操作@staticmethoddefadd_users_by_thread(username,password,session):user=U......
  • 为什么多线程会带来性能问题?
    为什么多线程会带来性能问题?什么是性能问题在上一篇中,我们已经学习了多线程带来的线程安全问题,但对于多线程而言,它不仅可能会带来线程安全问题,还有可能会带来性能问题,也许你会奇怪,我们使用多线程的最大目的不就是为了提高性能吗?让多个线程同时工作,加快程序运行速度,为什么反而会带来......
  • [java][代码]Java中创建多线程方法
     在Java中,创建多线程有多种方法。以下是一些常见的方法:1.继承Thread类通过继承Thread类并重写其run方法来创建线程。classMyThreadextendsThread{publicvoidrun(){//线程要执行的任务System.out.println("线程运行中...");}......
  • 多线程的使用-->3
    1.死锁在线程同步过程中,因为多线程争抢锁资源,所以有些线程会执行,有些线程会等待。如果线程A和线程B分别需要X和Y两个锁资源恰好A获得了X资源,准备争抢Y,而B获得了Y资源,准备争抢X,此时A和B就进入了一中死锁状态。如何解决死锁问题?①从业务逻辑层面解决让它们随机抢资源......
  • 在多线程环境下,如何解决 Java 函数失效的问题?,java 多线程处理数据
    在多线程环境下,Ja函数失效的问题是开发者常常遇到的一个挑战。多线程带来了并发执行的优势,但同时也增加了代码的复杂性,尤其是在涉及共享资源时,如果处理不当,可能会导致函数失效,甚至引发更严重的问题。本文将探讨一些常见的Ja函数失效原因,并提供相应的解决方法。我们需要了解函数失......
  • 多线程篇(ThreadLocal & 内存模型 & 伪共享(ThreadLocal ))(持续更新迭代)
    目录一、ThreadLocal1.前言2.简介3.与Synchronized的区别4.简单使用5.原理5.1.set5.2.get5.3.remove5.4.与Thread,ThreadLocalMap之间的关系5.常见使用场景场景一:存储用户Session场景二、数据库连接,处理数据库事务场景三、数据跨层传递(controller,servi......
  • 多线程篇(ThreadLocal & 内存模型 & 伪共享(内存可见性))(持续更新迭代)
    目录一、内存可见性问题(并发编程之美)二、Java内存模型(深入理解JVM第三版)1.简介2.硬件的效率与一致性3.Java内存模型3.1主内存与工作内存3.2内存间交互操作3.3对于volatile型变量的特殊规则3.4针对long和double型变量的特殊规则3.5原子性、可见性与有序性原......
  • WiFi基础(二):最新WiFi信道、无线OSI模型与802.11b/g/n
    liwen012024.09.01前言最近十几年,通信技术发展迅猛,通信标准更新频繁,有的设备还在使用802.11/b/g/n协议,有的已支持到WiFi6、WiFi7。而国内有关无线WiFi的书籍或资料却很少,就算能找着的,大多也是比较老旧。本文试图使用最新的数据来介绍WiFi相关的一些基础知识。关于WiF......
  • 多线程下载,并展示下载速度,支持断点下载
    为什么由于下载的文件较大,单线程下载会导致时间较长,影响体验,因此在串行程序基础上引入多线程,提高下载速度;实现功能设置指定下载线程数根据线程进行分段分段下载下载进度展示合并分段清理临时文件分段、合并需要用到RandomAccessFile此类的实例支持对随机访问文件的读......
  • 多线程篇(并发编程 - 进程&线程&协程&纤程&管程)(持续更新迭代)
    目录一、进程(Progress)1.进程2.僵尸进程2.1什么是僵尸进程2.2僵尸进程的危害2.3如何避免僵尸进程的产生3.参考链接二、线程(Thread)1.线程是什么?2.多线程2.1.概述2.2.多线程的好处2.3.多线程的代价3.线程模型(三种)3.1.一对一模型3.2.多对一模型3.3......