searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

java 中的并发

2022-12-23 13:26:25
84
0

名词解释

并发 vs 并行


并发(concurrent):一个处理器同时处理多个任务,无论上一个开始执行的任务是否完成,当前任务都可以开始执行,相反的概念是顺序(sequential)上一个开始执行的任务完成后,当前任务才能开始执行。
并行(parallel):多个处理器或者是多核的处理器同时处理多个不同的任务,多个任务执行单元,相反的概念是串行(serial)只有一个任务执行单元。

同步 vs 异步

同步:执行某个操作开始后就一直等着按部就班的直到操作结束
异步:执行某个操作后立即离开,后面有响应的话再来通知执行者

阻塞 vs 非阻塞

阻塞:某个操作需要的共享资源被占用了,只能等待,称为阻塞
非阻塞:某个操作需要的共享资源被占用了,不等待立即返回,并携带错误信息回去,期待重试
临界区:公共资源或者共享数据

Java 并发机制的底层实现

原子性(Atomicity):不可被中断的一个或一系列操作。

可见性(Visibility):当一个线程修改一个变量的值,新值对于其它线程是可以立即得知的。

顺序性(Ordering):如果在线程内观察,所有的操作都是有序的,如果在一个线程中观察另一个线程,所有操作都是无序的。“线程内表现为串行的语义”(Within-Thread As-If-Serial Semantics),“指令重排序”现象和“工作内存和主内存同步延迟”现象。

volatile

volatile 变量,用于确保将变量的更新操作同步到其它线程。volatile 变量是一种比 synchronized 关键字更轻量级的同步机制。

变量定义为volatile 后,它将具备两种特性:

1、变量可见性,当一个线程修改一个变量时,另一个线程能读到这个修改的值。

2、禁止指令重排序优化,编译器重排序,处理器重排序。

synchronized

一个变量在同一个时刻只允许一条线程对其进行 lock 操作。

  1. 原理:Monitor 对象,monitorenter, monitorexit 配对。
  2. 实现同步的基础:
    对于普通方法,锁的是当前实例对象。
    对于静态同步方法,锁的是当前类的 Class 对象。
    对于同步方法块,锁的是 synchronized 括号里配置的对象。
  3. 做了哪些优化?
    自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术来减少锁操作的开销。

CAS(Compare And Swap)

  1. 定义:比较并交换,乐观锁机制
  2. 使用场景:原子包 java.util.concurrent.atomic(锁自旋)
  3. CAS 三大问题:
    ABA 问题
    循环时间长开销大
    只能保证一个共享变量的原子操作

Java 并发编程的基础

线程简介

什么是线程

是操作系统能够进行运算调度的最小单位。大部分情况下,它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

为什么要使用多线程

更多的处理器核心

更快的响应时间

更好的编程模型

线程的优先级

线程的状态

状态名称

说明

NEW

尚未启动的线程状态,即线程创建,还未调用start方法

RUNNABLE

就绪状态(调用start,等待调度)+正在运行

BLOCKED

等待监视器锁时,陷入阻塞状态

WAITING

等待状态的线程正在等待另一线程执行特定的操作(如notify)

TIMED_WAITING

具有指定等待时间的等待状态

TERMINATED

线程完成执行,终止状态

线程的状态变迁

创建、启动、运行、终止线程

JAVA线程实现/创建方式

继承Thread类,实现Runnable接口

start 与 run 区别

终止线程 4 种方式

正常运行结束

使用退出标志退出线程

Interrupt 方法结束线程

stop 方法终止线程(线程不安全)

线程基本方法

wait,notify,notifyAll,sleep,join,yield

线程上下文切换

进程

上下文

寄存器

程序计数器

PCB process control block-“切换桢”

上下文切换的活动

引起线程上下文切换的原因

线程调度方式

抢占式,协同式

线程间的通信

volatile 和 synchronized

等待/通知机制

管道输入/输出流

Thread.join() 的使用

ThreadLocal

Java中的线程池

线程池的好处

  1. 降低资源消耗;
  2. 提高响应速度;
  3. 提高线程的可管理性;

线程池的实现原理

ThreadPoolExecutor 执行示意图

ThreadPoolExecutor 执行任务示意图

线程池的使用

线程池的创建

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          @NotNull TimeUnit unit,
                          @NotNull BlockingQueue<Runnable> workQueue,
                          @NotNull ThreadFactory threadFactory,
                          @NotNull RejectedExecutionHandler handler)

corePoolSize – the number of threads to keep in the pool, even if they are idle, unless allowCoreThreadTimeOut is set

maximumPoolSize – the maximum number of threads to allow in the pool

keepAliveTime – when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.

unit – the time unit for the keepAliveTime argument

workQueue – the queue to use for holding tasks before they are executed. This queue will hold only the Runnable tasks submitted by the execute method.

threadFactory – the factory to use when the executor creates a new thread

handler – the handler to use when execution is blocked because the thread bounds and queue capacities are reached

当所有的核心线程都在干活时,新添加的任务会被添加到这个队列中等待处理,如果队列满了,则新建非核心线程执行任务。

向线程池提交任务

调用 execute() 提交不需要返回值的任务。
调用 submit() 提交需要返回值的任务。

关闭线程池

调用 shutdown() 或者 shutdownNow() 方法。
原理是遍历线程池中的工作线程,然后逐个调用线程的 interrupt 方法中断线程,所以无法响应中断的任务可能永远无法终止。

合理配置线程池

线程池监控

参数配置

corePoolSize >= requestsPerSecond * secondsPerRequest
maximumPoolSize >= maximumRequestsPerSecond * secondsPerRequest
queueCapacity <= maximumPoolSize * maxWaitTime / timePerRequest

 

参考资料

0条评论
0 / 1000
朱****斌
10文章数
0粉丝数
朱****斌
10 文章 | 0 粉丝
原创

java 中的并发

2022-12-23 13:26:25
84
0

名词解释

并发 vs 并行


并发(concurrent):一个处理器同时处理多个任务,无论上一个开始执行的任务是否完成,当前任务都可以开始执行,相反的概念是顺序(sequential)上一个开始执行的任务完成后,当前任务才能开始执行。
并行(parallel):多个处理器或者是多核的处理器同时处理多个不同的任务,多个任务执行单元,相反的概念是串行(serial)只有一个任务执行单元。

同步 vs 异步

同步:执行某个操作开始后就一直等着按部就班的直到操作结束
异步:执行某个操作后立即离开,后面有响应的话再来通知执行者

阻塞 vs 非阻塞

阻塞:某个操作需要的共享资源被占用了,只能等待,称为阻塞
非阻塞:某个操作需要的共享资源被占用了,不等待立即返回,并携带错误信息回去,期待重试
临界区:公共资源或者共享数据

Java 并发机制的底层实现

原子性(Atomicity):不可被中断的一个或一系列操作。

可见性(Visibility):当一个线程修改一个变量的值,新值对于其它线程是可以立即得知的。

顺序性(Ordering):如果在线程内观察,所有的操作都是有序的,如果在一个线程中观察另一个线程,所有操作都是无序的。“线程内表现为串行的语义”(Within-Thread As-If-Serial Semantics),“指令重排序”现象和“工作内存和主内存同步延迟”现象。

volatile

volatile 变量,用于确保将变量的更新操作同步到其它线程。volatile 变量是一种比 synchronized 关键字更轻量级的同步机制。

变量定义为volatile 后,它将具备两种特性:

1、变量可见性,当一个线程修改一个变量时,另一个线程能读到这个修改的值。

2、禁止指令重排序优化,编译器重排序,处理器重排序。

synchronized

一个变量在同一个时刻只允许一条线程对其进行 lock 操作。

  1. 原理:Monitor 对象,monitorenter, monitorexit 配对。
  2. 实现同步的基础:
    对于普通方法,锁的是当前实例对象。
    对于静态同步方法,锁的是当前类的 Class 对象。
    对于同步方法块,锁的是 synchronized 括号里配置的对象。
  3. 做了哪些优化?
    自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术来减少锁操作的开销。

CAS(Compare And Swap)

  1. 定义:比较并交换,乐观锁机制
  2. 使用场景:原子包 java.util.concurrent.atomic(锁自旋)
  3. CAS 三大问题:
    ABA 问题
    循环时间长开销大
    只能保证一个共享变量的原子操作

Java 并发编程的基础

线程简介

什么是线程

是操作系统能够进行运算调度的最小单位。大部分情况下,它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

为什么要使用多线程

更多的处理器核心

更快的响应时间

更好的编程模型

线程的优先级

线程的状态

状态名称

说明

NEW

尚未启动的线程状态,即线程创建,还未调用start方法

RUNNABLE

就绪状态(调用start,等待调度)+正在运行

BLOCKED

等待监视器锁时,陷入阻塞状态

WAITING

等待状态的线程正在等待另一线程执行特定的操作(如notify)

TIMED_WAITING

具有指定等待时间的等待状态

TERMINATED

线程完成执行,终止状态

线程的状态变迁

创建、启动、运行、终止线程

JAVA线程实现/创建方式

继承Thread类,实现Runnable接口

start 与 run 区别

终止线程 4 种方式

正常运行结束

使用退出标志退出线程

Interrupt 方法结束线程

stop 方法终止线程(线程不安全)

线程基本方法

wait,notify,notifyAll,sleep,join,yield

线程上下文切换

进程

上下文

寄存器

程序计数器

PCB process control block-“切换桢”

上下文切换的活动

引起线程上下文切换的原因

线程调度方式

抢占式,协同式

线程间的通信

volatile 和 synchronized

等待/通知机制

管道输入/输出流

Thread.join() 的使用

ThreadLocal

Java中的线程池

线程池的好处

  1. 降低资源消耗;
  2. 提高响应速度;
  3. 提高线程的可管理性;

线程池的实现原理

ThreadPoolExecutor 执行示意图

ThreadPoolExecutor 执行任务示意图

线程池的使用

线程池的创建

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          @NotNull TimeUnit unit,
                          @NotNull BlockingQueue<Runnable> workQueue,
                          @NotNull ThreadFactory threadFactory,
                          @NotNull RejectedExecutionHandler handler)

corePoolSize – the number of threads to keep in the pool, even if they are idle, unless allowCoreThreadTimeOut is set

maximumPoolSize – the maximum number of threads to allow in the pool

keepAliveTime – when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.

unit – the time unit for the keepAliveTime argument

workQueue – the queue to use for holding tasks before they are executed. This queue will hold only the Runnable tasks submitted by the execute method.

threadFactory – the factory to use when the executor creates a new thread

handler – the handler to use when execution is blocked because the thread bounds and queue capacities are reached

当所有的核心线程都在干活时,新添加的任务会被添加到这个队列中等待处理,如果队列满了,则新建非核心线程执行任务。

向线程池提交任务

调用 execute() 提交不需要返回值的任务。
调用 submit() 提交需要返回值的任务。

关闭线程池

调用 shutdown() 或者 shutdownNow() 方法。
原理是遍历线程池中的工作线程,然后逐个调用线程的 interrupt 方法中断线程,所以无法响应中断的任务可能永远无法终止。

合理配置线程池

线程池监控

参数配置

corePoolSize >= requestsPerSecond * secondsPerRequest
maximumPoolSize >= maximumRequestsPerSecond * secondsPerRequest
queueCapacity <= maximumPoolSize * maxWaitTime / timePerRequest

 

参考资料

文章来自个人专栏
文章 | 订阅
0条评论
0 / 1000
请输入你的评论
0
0