【并发编程技术】「技术辩证分析」在并发编程模式下进行线程安全以及活跃性问题简析

简介: 【并发编程技术】「技术辩证分析」在并发编程模式下进行线程安全以及活跃性问题简析

什么是线程安全?


线程安全,有两个重要的特征说明:“共享”和“可变”。


  • 共享是指可以被多个线程同时访问;
  • 可变是指变量的值在生命周期内是可以变化的;



如何实现线程安全


  • 一个对象是否需要线程安全的,取决于它是否被多个线程访问;
  • 如何保证一个对象的线程安全,则需要采用同步机制来协同对对象可变状态的访问;
  • 给线程安全下一个明确的定义:当多个线程访问这个对象或者资源时,如果这个对象或资源始终都能表现出数据的一致性的状态,那么就称这个对象或者资源是线程安全的;



数据资源的有无状态化


  • 无状态的对象一定是线程安全的。


  • 有状态的对象,多线程环境下,多个线程共享资源,且进行的不是原子性操作,这个时候就要考虑线程的安全控制问题


比如:count++,其实是不具备原子性的,因为这个步骤实际会被拆分为三个步骤,即 读取、修改和写入,而这三个步骤有可能在某个时刻因CPU时间片的切换问题,而只执行其中一两个步骤,这就不具备原子性。

image.png


原子化能力支持


在Java中,为了解决这个问题,java.util.concurrent.atomic包提供了很多的类,来保证数据操作的原子性,比如我们之前的程序可以修改为


  • 基本数据类型 AtomicInteger
  • 数组类型 AtomicIntegerArray
AtomicInteger integer = new AtomicInteger(0);
integer.incrementAndGet()
复制代码


内部的原理是采用了CAS机制



那么什么是CAS机制?


CAS有人翻译为Compare And Set或Compare And Swap都是正确的。


多线程并发执行的状态下,锁的状态改变,基本都是使用CAS原理,它有一个比较别扭的叫法“CPU硬件同步原语”,算法是基于CPU硬件的,原子性操作,不会被其他线程打断。


CAS的算法,比较当前值和期望的值是否相等,如果相等,则将当前值赋予一个新值。


再比如修改一个Boolean的类型的变量的值,我们也可以采用

private AtomicBoolean atomicBoolean = new AtomicBoolean(false);
public void lock(){
    //期望是false,如果是false,则可以修改为true
    atomicBoolean.compareAndSet(false, true);
}
复制代码



同步锁机制支持


只要程序中存在“先判断,再更新”,那么就要保证这两个操作在一个原子操作里面,才能保证线程安全。

public synchronized int getCount(){
    return count++;
}
复制代码


Java锁机制的一些特点


监视锁、互斥锁、可重入锁都是在这个锁的特点。


  • 监视锁:java的每一个对象都可以用来做监视锁,也就是为什么我们的wait、notify方法定义在Object类的原因。
  • 互斥锁:表示最多只有一个线程可以持有这把锁。
  • 可重入锁:是指当线程A请求一个由线程B持有的锁时,线程B会进入阻塞状态;而如果线程A如果再访问另一段代码,而这个代码的锁是已经被线程A持有的,这个时候请求是可以成功的,这就叫可重入。



Java锁机制的简单原理


JVM为每个锁设置两个属性,获取计数值和所有者线程,当计数值为0时,这个锁就被认为是没有被任何线程持有,当线程请求一个未被持有的锁时,JVM将记录锁的持有者,并且计数值+1。


如果同一个线程再次获取这个锁,则计数值将递增,而当线程退出同步代码块时,计数器会相应递减,当计数值为0,这个锁将被释放。




活跃性问题


承接上面解决安全性的问题分析,锁机制会存在活跃性问题,比如:死锁,饥饿,活锁,这些都是属于活跃性问题。


死锁

多个线程,各自占对方的资源,都不愿意释放,从而造成死锁,A线程需要等待的锁被B线程占用,而B线程需要的等待的锁被A线程占用,所以相互都不释放,于是就陷入了死锁。



饥饿

多个线程访问同一个同步资源,有些线程总是没有机会得到互斥锁,这种就叫做饥饿。



出现饥饿的三种情况


  1. 高优先级的线程吞噬了低优先级的线程的CPU时间片
  • 理论上来说,线程优先级高的线程会比线程优先级低的线程获得更多的执行机会,但是java的线程优先级不是绝对出现这样的效果。
  • 一般而言:优先级高的出现频率会比优先级低的高很多
  • 不同的操作系统对线程的优先级支持是不同的,规定是在1-10之间,java通过3个常量来屏蔽这种操作系统的底层差异化。
  1. 线程被永久阻塞在等待进入同步代码块的状态
  2. 等待的线程永远不被唤醒


建议大家采用公平锁来代替synchronized这种互斥锁


活锁


两个人在走廊上碰见,大家都互相很有礼貌,互相礼让,A从左到右,B也从从左转向右,发现又挡住了地方,继续转换方向,但又碰到了,反反复复,一直没有机会运行下去。




相关文章
|
17天前
|
Java 开发者
解锁并发编程新姿势!深度揭秘AQS独占锁&ReentrantLock重入锁奥秘,Condition条件变量让你玩转线程协作,秒变并发大神!
【8月更文挑战第4天】AQS是Java并发编程的核心框架,为锁和同步器提供基础结构。ReentrantLock基于AQS实现可重入互斥锁,比`synchronized`更灵活,支持可中断锁获取及超时控制。通过维护计数器实现锁的重入性。Condition接口允许ReentrantLock创建多个条件变量,支持细粒度线程协作,超越了传统`wait`/`notify`机制,助力开发者构建高效可靠的并发应用。
37 0
|
5天前
|
API Windows
揭秘网络通信的魔法:Win32多线程技术如何让服务器化身超级英雄,同时与成千上万客户端对话!
【8月更文挑战第16天】在网络编程中,客户/服务器模型让客户端向服务器发送请求并接收响应。Win32 API支持在Windows上构建此类应用。首先要初始化网络环境并通过`socket`函数创建套接字。服务器需绑定地址和端口,使用`bind`和`listen`函数准备接收连接。对每个客户端调用`accept`函数并在新线程中处理。客户端则通过`connect`建立连接,双方可通过`send`和`recv`交换数据。多线程提升服务器处理能力,确保高效响应。
20 6
|
4天前
|
存储 缓存 安全
深度剖析Java HashMap:源码分析、线程安全与最佳实践
深度剖析Java HashMap:源码分析、线程安全与最佳实践
|
9天前
|
缓存 Java 数据处理
Java中的并发编程:解锁多线程的力量
在Java的世界里,并发编程是提升应用性能和响应能力的关键。本文将深入探讨Java的多线程机制,从基础概念到高级特性,逐步揭示如何有效利用并发来处理复杂任务。我们将一起探索线程的创建、同步、通信以及Java并发库中的工具类,带你领略并发编程的魅力。
|
10天前
|
消息中间件 安全 Kafka
"深入实践Kafka多线程Consumer:案例分析、实现方式、优缺点及高效数据处理策略"
【8月更文挑战第10天】Apache Kafka是一款高性能的分布式流处理平台,以高吞吐量和可扩展性著称。为提升数据处理效率,常采用多线程消费Kafka数据。本文通过电商订单系统的案例,探讨了多线程Consumer的实现方法及其利弊,并提供示例代码。案例展示了如何通过并行处理加快订单数据的处理速度,确保数据正确性和顺序性的同时最大化资源利用。多线程Consumer有两种主要模式:每线程一个实例和单实例多worker线程。前者简单易行但资源消耗较大;后者虽能解耦消息获取与处理,却增加了系统复杂度。通过合理设计,多线程Consumer能够有效支持高并发数据处理需求。
32 4
|
17天前
|
Java API 开发者
Java中的并发编程:解锁多线程的潜力
在数字化时代的浪潮中,并发编程已成为软件开发的核心技能之一。本文将深入探讨Java中的并发编程概念,通过实例分析与原理解释,揭示如何利用多线程提升应用性能和响应性。我们将从基础的线程创建开始,逐步过渡到高级的同步机制,并探讨如何避免常见的并发陷阱。读者将获得构建高效、稳定并发应用所需的知识,同时激发对Java并发更深层次探索的兴趣。
27 2
|
4天前
|
算法 安全 Java
深入解析Java多线程:源码级别的分析与实践
深入解析Java多线程:源码级别的分析与实践
|
5天前
|
NoSQL Redis
Lettuce的特性和内部实现问题之在同步调用模式下,业务线程是如何拿到结果数据的
Lettuce的特性和内部实现问题之在同步调用模式下,业务线程是如何拿到结果数据的
|
7天前
三个线程交替打印ABC:技术深度解析与实战应用
【8月更文挑战第14天】在并发编程中,实现多个线程之间的精确协同工作是一项既具挑战性又极具实用价值的任务。今天,我们将深入探讨一个经典问题:如何使用三个线程交替打印字符A、B、C,且每个字符连续打印三次,之后循环进行。这个问题不仅考验了我们对线程同步机制的理解,还锻炼了我们在复杂并发场景下的设计能力。
13 0
|
13天前
|
Java 数据库
Java中的并发编程:深入理解线程池
在Java的并发编程领域,线程池是提升性能和资源管理的关键工具。本文将通过具体实例和数据,探讨线程池的内部机制、优势以及如何在实际应用中有效利用线程池,同时提出一个开放性问题,引发读者对于未来线程池优化方向的思考。
31 0

相关实验场景

更多