
Java并发编程
文章平均质量分 77
Java并发编程
A minor
本来无一物,何处惹尘埃
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
【Java并发编程】操作系统基础(一):进程、线程、线程模型
1.进程与线程1.1 进程资源分配单位。创建慢,上下文切换开销大进程状态:从上图可以看出,进程运行中只有三种状态:ready,running,waiting事实上还存在进程挂起状态,原因是为了满足CPU的某些需求,会将一些处于阻塞/就绪的进出交换出内存详细可以参考这篇博客。1.2 线程(轻量级进程)CPU调度单位。线程间共享进程资源。在Linux下其实本并没有线程,只是为了迎合开发者口味,搞了个轻量级进程出来就叫做了线程。轻量级进程和进程一样,都有自己独立的task_struct进原创 2020-09-14 21:15:26 · 1048 阅读 · 0 评论 -
【Java并发编程】操作系统基础(二):内核态、用户态
Linux & Unix架构图:从图上我们可以看出来通过系统调用将Linux整个体系分为用户态和内核态(或者说内核空间和用户空间)。系统调用为了使应用程序访问到内核管理的资源例如CPU,内存,I/O。内核必须提供一组通用的访问接口,这些接口就叫系统调用。例如:用户态想要申请一块20K大小的动态内存,就需要brk系统调用,将数据段指针向下偏移,如果用户态多处申请20K动态内存,同时又释放呢?这个内存的管理就变得非常的复杂。Shell顾名思义,就是外壳的意思。就好像把内核包裹起来的外壳。它原创 2020-09-14 22:07:13 · 1891 阅读 · 0 评论 -
【Java并发编程】操作系统基础(三):上下文切换的三种情况
我们都知道,Linux 是一个多任务操作系统,它支持远大于 CPU 数量的任务同时运行。当然,这些任务实际上并不是真的在同时运行,而是因为系统在很短的时间内,将 CPU 轮流分配给它们,造成多任务同时运行的错觉。而在每个任务运行前,CPU 都需要知道任务从哪里加载、又从哪里开始运行,也就是说,需要系统事先帮它设置好CPU 寄存器和程序计数器什么是 CPU 上下文?CPU 寄存器和程序计数器就是 CPU 上下文,因为它们都是 CPU 在运行任何任务前,必须的依赖环境。CPU 寄存器是 CPU 内置的原创 2020-09-14 22:39:35 · 1385 阅读 · 0 评论 -
【Java并发编程】操作系统基础(四):进程调度时机、模式、算法
1.调度时机在创建一个新进程之后,需要决定是运行父进程还是运行子进程。由于这两种进程都处于就绪状态,所以这是一种正常的调度决策,可以任意决定。在一个进程退出时必须做出调度决策。一个进程不再运行,所以必须从就绪进程集中选择另外某个进程。如果没有就绪的进程,通常会运行一个系统提供的空闲进程。当一个进程在阻塞I/O和信号量上或由于其他原因阻塞时,必须选择另一个进程运行。在一个I/O中断发生时,必须做出调度决策。如果中断来自I/O设备,而该设备现在完成了工作,某些阻塞的等待该I/O进程就成为可运行的就绪进原创 2020-09-14 22:23:56 · 2062 阅读 · 0 评论 -
【Java并发编程】操作系统基础(五):Java 线程模型、线程调度算法
1 Java线程模型Java语言的线程,从规范的角度来说是不强制要求任何具体的实现方式的。采用1:1、N:1、M:N模型都可以。先放个传送门:RednaxelaFX:JVM中的线程模型是用户级的么?N : 1(JDK2前)Java线程在JDK1.2之前,是基于称为“绿色线程”(Green Threads)的用户线程实现的,而在JDK1.2中,线程模型替换为基于操作系统原生线程模型来实现。因此,在目前的JDK版本中,操作系统支持怎样的线程模型,在很大程度上决定了Java虚拟机的线程是怎样映射的,这点在不原创 2020-09-14 19:29:08 · 2304 阅读 · 0 评论 -
【Java并发编程】Java多线程(一):线程基础
1.线程介绍1.1 线程状态NEW(创建):线程刚被创建,但未启动,还未调用startRUNNABLE(可运行):调用了 strat 方法;可能在CPU执行,也有可能没有TIMED_WAITING(计时等待):让出CPU,计时休眠;sleep(持锁)WAITINIT(等待):让出CPU,休眠;无锁park->unpark,有锁wait->notify(会释放锁)BLOCKED(阻塞):等待获得 monitor lock 锁,是对于 synchronized 而言TERMINATE原创 2020-09-16 00:25:05 · 1947 阅读 · 1 评论 -
【Java并发编程】Java多线程(二):多线程一定好吗?线程阻塞时占用CPU吗?
1.多线程一定好吗1.1 适用场景阻塞等待时充分利用CPU当程序发生阻塞的操作时候,例如IO等待,CPU将就空闲下来了。而使用多线程,当一些线程发生阻塞的时候,另一些线程则仍能利用CPU,而不至于让CPU一直空闲。利用CPU的多核并行计算能力现在的CPU基本上都是多核的。使用多线程,可以利用多核同时执行多个线程,而不至于单线程时一个核心满载,而其他核心空闲。1.2 多线程弊端线程切换是有开销的,这会导致程序运行变慢。多线程程序必须非常小心地同步代码,否则会引起死锁。多线程程序极难调试原创 2020-09-14 20:09:30 · 6759 阅读 · 0 评论 -
【Java并发编程】Java多线程(三):创建任务 --Runnable、Callable
1.创建线程任务方案一:Runnablerunnable无返回值,run实现线程逻辑public interface Runnable { public abstract void run();}2.创建线程任务方案二:Callable2.1 Callablecallable有返回值(V),call实现线程逻辑public interface Callable<V> { V call() throws Exception;}2.2 FutureCallab原创 2020-09-16 15:57:04 · 2790 阅读 · 0 评论 -
【Java并发编程】Java多线程(四):FutureTask 源码分析
前言:【Java并发编程】Java多线程(三):Runnable、Callable --创建任务的方式在上一篇文章的末尾我们通过两个问题,引出了 FutureTask 及其设计思路,先来回顾一下:问题一:Callable 与 Future都是接口,怎么实现通过 Future 控制 Callable 呢?答:可以创建一个中间类实现 Future接口,然后将 Callable 实例组合进来,最后通过 Future 接口中的方法实现控制。问题二:另外,这里还要考虑一个问题,Runnable 和 Cal.原创 2021-02-25 02:06:22 · 360 阅读 · 0 评论 -
【Java并发编程】Java多线程(五):关于线程的几个问题
1.子线程 1 去等待子线程 2 执行完成之后才能执行,如何去实现?答:这里考察的就是 Thread.join 方法,我们可以这么做:@Testpublic void testJoin2() throws Exception { // 线程2 Thread thread2 = new Thread(new Runnable() { public void run() {...} }); // 线程1 Thread thread1 = new Thread(new Runna原创 2020-09-16 00:32:13 · 1717 阅读 · 1 评论 -
【Java并发编程】并发:线程安全三要素及解决方案
1.可见性多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看到修改的值。解决方案1)JMM 提供了 volatile2.有序性若在本线程内观察,所有操作是有有序的若在一个线程观察另一个线程,所有操作时无序的在 JVM 中,为了效率允许编译器和处理器对指令进行重排序解决方案1)线程内:as-if-seria,单线程中重排序后不影响执行结果2)多线程:JMM 提供了 happens-before 规则程序顺序规则:一个线程中的每个操作,happens-befor原创 2021-02-25 17:21:04 · 574 阅读 · 5 评论 -
【Java并发编程】volatile(一):保证多线程下的可见性
首先抛出一个问题:“volatile 这个关键字有什么作用?”。常见的回答或许有两种:一种是把 volatile 当成一种锁机制,认为给变量加上了 volatile,就好像是给函数加了 sychronized 关键字一样,不同的线程对于特定变量的访问会去加锁;另一种是把 volatile 当成一种原子化的操作机制,认为加了 volatile 之后,对于一个变量的自增的操作就会变成原子性的事实上,这两种理解都是完全错误的。volatile 关键字的核心知识点,要关系到 Java 内存模型(JMM,J原创 2020-09-16 21:49:56 · 3301 阅读 · 3 评论 -
【Java并发编程】volatile(二):防止指令重排序
在上一篇文章我们通过三个示例介绍了 volatile 能够保证多线程环境下的可见性,而 volatile关键字另一个作用就是禁止指令重排优化,从而避免多线程环境下程序出现乱序执行的现象。下面看一个非常典型的禁止重排优化的例子DCL,如下:public class Singleton { private static Object lock = new Object(); private static Singleton instance = null; private Singlet原创 2021-04-14 16:07:31 · 557 阅读 · 0 评论 -
【Java并发编程】volatile(三):内存语义的实现原理
1.可见性多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看到修改的值**happens-before **程序顺序规则:一个线程中的每个操作,happens-before于该线程任意后续操作start()规则:如果线程A执行操作threadB.start(),那么A线程中threadB.start()happens-beforeB的任意操作join()规则:如果线程A执行操作thread.join(),那么线程B的任意操作happens-before于A从threadB.原创 2020-09-16 21:33:41 · 1537 阅读 · 1 评论 -
【Java并发编程】原子操作(一):计算机如何实现原子操作
原子(atom)本意是“不能被进一步分割的小粒子”,而原子操作(atomic operation)意为”不可被中断的一个或一系列操作” 。在多处理器上实现原子操作就变得有点复杂。本文让我们一起来聊一聊在Inter处理器和Java里是如何实现原子操作的。术语名称英文缓存行Cache line比较并交换Compare and SwapCPU流水线CPU pipeline内存顺序冲突Memory order violation下面我们就来看看处理器如何实现原原创 2021-04-14 19:55:39 · 488 阅读 · 0 评论 -
【Java并发编程】原子操作(二):四种 Atomic 原子类详析(CAS+自旋)
Atomic 打头的原子操作类有很多,涉及到 Java 常用的数字类型的,基本都有相应的 Atomic 原子操作类,如下图所示:Atomic 打头的原子操作类,在高并发场景下,都是线程安全的,我们可以放心使用。AtomicInteger主要是调用Unsafe类的CAS操作,下面是 AtomicInteger 的部分源码:public class AtomicInteger extends Number implements java.io.Serializable { // 注:原创 2020-09-21 20:45:18 · 2324 阅读 · 0 评论 -
【Java并发编程】synchronized(一):同步 --生产者消费者问题
在文章的开头先明确几个概念:并发:多个线程同时操作同一个对象,并要修改其实例变量final 修饰的实例变量线程安全,因为不可变只能初始化一次锁:OS 的调度无法满足同步的需求,需要程序通过调度算法协助调度synchronized:JVM 级别锁Lock:api 级别synchronized:对象的锁,锁的代码通过只允许一个线程执行 sync 内代码,保证了可见性,有序性,原子性并发要求线程交替执行(时间片),而拿了锁会一直将任务执行完再释放(即使n时间片)Java 的原创 2021-02-25 04:17:19 · 346 阅读 · 2 评论 -
【Java并发编程】synchronized(二):通信 --一个容器问题
要求:实现一个容器,提供两个方法,add,size写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数到5个时,线程2给出提示并结束1.方案一:volatilepublic class MyContainer<T> { // 复用 ArrayList // 注:这里使用 volatile 保证两个线程都能感知到修改 volatile List<T> list = new ArrayList<>(); // 使用 List原创 2021-02-25 15:39:56 · 206 阅读 · 4 评论 -
【Java并发编程】synchronized(三):使用注意事项、死锁示例
在文章的开头先明确几个概念:并发:多个线程同时操作同一个对象,并要修改其实例变量final 修饰的实例变量线程安全,因为不可变只能初始化一次锁:OS 的调度无法满足同步的需求,需要程序通过调度算法协助调度synchronized:JVM 级别锁Lock:api 级别synchronized:对象的锁,锁的代码通过只允许一个线程执行 sync 内代码,保证了可见性,有序性,原子性并发要求线程交替执行(时间片),而拿了锁会一直将任务执行完再释放(即使n时间片)Java 的原创 2021-02-25 00:57:41 · 374 阅读 · 2 评论 -
【Java并发编程】synchronized(四):信号量、互斥量原理分析对比
1 临界区1.1 简介在早期计算机系统中,只有一个任务进程在执行,并不存在资源的共享与竞争。随着技术和需求的飞速发展,单个CPU通过时间分片在一段时间内同时处理多个任务进程,当多个进程对共享资源进行并发访问,就引起了进程间的竞态。这其中包括了我们所熟知的SMP(对称多处理器结构)系统,多核间的相互竞争,单CPU中断和进程间的相互抢占等诸多问题。更具体的说,对某段代码而言,可能会在程序中多次被执行(多线程便是典型的场景),每次执行的过程我们称作代码的执行路径,当两个或多个代码路径要竞争共同的资源的时候,原创 2020-09-17 00:00:10 · 1703 阅读 · 0 评论 -
【Java并发编程】synchronized(五):锁膨胀原理分析(JDK6后)
前言:【Java并发编程】synchronized(二):重量级锁原理分析(JDK6前)JDK6 为了减少获得锁和释放锁带来的性能消耗,引入了“偏向锁”和“轻量级锁”:锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态。锁可以升级但不能降级。在对象头的 Mark Word 中保存了不同的锁状态:1.偏向锁特点:只有一个线程执行原理:CAS注:偏向锁在Java 6和Java 7里是默认启用的。由于偏向锁是为了在只有一个线程执行同步块时提高性能,如果你确定应.原创 2021-02-24 23:34:51 · 404 阅读 · 2 评论 -
【Java并发编程】synchronized(六):偏向锁与 HashCode 能共存吗?
原文链接:https://blog.csdn.net/saintyyu/article/details/108295657我们知道,Java 对象头的结构如下:内容说明备注Mark Word存储对象的Mark Word信息-Class Metadata Address存储指向对象存储类型的指针-Array Length数组的长度只有数组对象有该属性其中,在32位下,Mark Word 的存储结构如下:在64位下,Mark Word的存储结构如下.转载 2021-03-15 18:40:47 · 1297 阅读 · 3 评论 -
【Java并发编程】synchronized(七):重量级锁原理分析
在文章的开头先明确几个概念:并发:多个线程同时操作同一个对象,并要修改其实例变量final修饰的实例变量线程安全,因为不可变只能初始化一次锁:OS的调度无法满足同步的需求,需要程序通过调度算法协助调度synchronized:jvm级别锁Lock:api界别synchronize:对象的锁,锁的代码通过只允许一个线程执行sync内代码,保证了可见性,有序性,原子性并发要求线程交替执行(时间片),而拿了锁会一直将任务执行完再释放(即使n时间片)java的线程通信实际是共原创 2020-09-18 00:27:29 · 3456 阅读 · 0 评论 -
【Java并发编程】synchronized(八):优化方案(锁消除、锁粗化)
1.synchronized优化方案1.1 锁消除锁消除即删除不必要的加锁操作。虚拟机即时编辑器在运行时,对一些“代码上要求同步,但是被检测到不可能存在共享数据竞争”的锁进行消除。根据代码逃逸技术,如果判断到一段代码中,堆上的数据不会逃逸出当前线程,那么可以认为这段代码是线程安全的,不必要加锁。看下面这段程序:public class SynchronizedTest { public static void main(String[] args) { Synchroni原创 2020-09-18 00:30:48 · 2949 阅读 · 2 评论 -
【Java并发编程】synchronized(九):对比总结 ReentrantLock
多线程和并发性并不是什么新内容,但是 Java 语言设计中的创新之一就是,它是第一个直接把跨平台线程模型和正规的内存模型集成到语言中的主流语言。核心类库包含一个 Thread 类,可以用它来构建、启动和操纵线程,Java 语言包括了跨线程传达并发性约束的构造 —— synchronized 和 volatile 。在简化与平台无关的并发类的开发的同时,它决没有使并发类的编写工作变得更繁琐,只是使它变得更容易了。1.简单回顾1.1 synchronized把代码块声明为 synchronized,有两个转载 2020-09-23 02:09:34 · 1247 阅读 · 0 评论 -
【Java并发编程】ThreadLocal(一):使用示例
下面启动 9 个子线程,每个子线程都将名字(thread - i)存在同一个变量中,然后再打印出来。可以想到,如果同一个变量可以做到线程间隔离(互补影响),控制台正确的结果应该是 thread - 0 到 thread - 8。下面就分别演示演示这个变量的两种实现:1.普通变量String ,2.ThreadLocal<String>1.普通变量public class StringTest { // 保存线程名的普通变量value private String value;原创 2021-03-23 13:25:43 · 272 阅读 · 0 评论 -
【Java并发编程】ThreadLocal(二):从设计思路到源码分析
在开始看源码之前,我们必须要知道ThreadLocal是干什么的:ThreadLocal 适用于每个线程需要自己独立的实例且该实例需要在多个方法中被使用(相同线程数据共享),也就是变量在线程间隔离(不同的线程数据隔离)而在方法或类间共享的场景。在文章开头先解决一个问题:如何实现线程之间数据隔离?空间换时间思路:既然要线程隔离就不应该大家在一起,应该每个线程都有独自一块空间为了能存多个值,应该是个数组 --> T【】为了能指定存取,应该是Map形式 --> Entry【】将相原创 2020-10-01 22:58:28 · 15726 阅读 · 4 评论 -
【Java并发编程】ThreadLocal(三):内存泄漏问题分析
首先来看两个概念:内存溢出、内存泄漏内存溢出: Memory overflow,没有足够的内存提供申请者使用内存泄漏: Memory Leak,程序中已经动态分配的堆内存由于某种原因, 程序未释放或者无法释放, 造成系统内部的浪费, 导致程序运行速度减缓甚至系统崩溃等严重结果. 内存泄漏的堆积终将导致内存溢出我们下面就来看看 ThreadLocal 为什么会出现内存泄漏问题。图中左边是栈,右边是堆。线程的一些局部变量和引用使用的内存属于 Stack(栈)区,而普通的对象是存储在Heap(堆)区原创 2021-03-22 14:40:59 · 566 阅读 · 0 评论 -
【Java并发编程】自旋锁(转)
2.1 自旋锁自旋锁的实现是为了保护一段短小的临界区操作代码,保证这个临界区的操作是原子的,从而避免并发的竞争。在Linux内核中,自旋锁通常用于包含内核数据结构的操作,你可以看到在许多内核数据结构中都嵌入有spinlock,这些大部分就是用于保证它自身被操作的原子性,在操作这样的结构体时都经历这样的过程:上锁-操作-解锁。如果内核控制路径发现自旋锁“开着”(可以获取),就获取锁并继续自己的执行。相反,如果内核控制路径发现锁由运行在另一个CPU上的内核控制路径“锁着”,就在原地“旋转”,反复执行一条紧凑转载 2021-04-14 22:57:56 · 196 阅读 · 0 评论