读书笔记之Java并发编程的艺术

129 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情

进程和线程

定义

进程

进程是并发执行程序在执行过程中资源分配和管理的基本单位(资源分配的最小单位)。

  • 进程可以理解为一个应用程序的执行过程,应用程序一旦执行,就是一个进程。
  • 每个进程都有自己独立的地址空间,每启动一个进程,系统就为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段。
线程

程序执行的最小单位

为什么要有线程?

每个进程都有自己的地址空间,即进程空间,在网络或多用户环境下,一个服务器通常需要接收大量不确定数量用户的并发请求,为每一个请求都创建一个进程显然行不通(系统开销大,响应用户请求效率低),因此操作系统中线程概念被引进。

区别

  1. 地址空间:统一进程的所有线程共享进程的地址空间,而不同的进程之间的地址空间是独立的;
  2. 资源拥有:同一进程的所有线程共享本进程的资源,如内存、CPU、IO等。进程之间的资源是独立的,无法共享;
  3. 执行过程:每一个进程可以说就是一个可执行的应用程序,每一个独立的进程都有一个程序执行的入口,顺序执行序列。但是线程不能够独立执行,必须依存在应用程序中,由程序的多线程控制机制进行控制;
  4. 健壮性:因为同一进程中的所有线程共享此进程中的资源,因此当一个线程发生崩溃时,此进程也发生崩溃。但是各个进程之间的资源时独立的,因此当一个进程发生崩溃时,不会影响其他进程。因此进程比线程健壮;

进程和线程的选择取决条件

因为进程时资源分配的最小单位,线程是程序执行的最小单位,以及进程与线程之间的健壮性来考虑

  1. 在程序中,如果需要频繁创建和销毁的场景,使用线程。因为进程创建和销毁开销很大(需要不停地分配资源),但是线程频繁的调用只是改变CPU的执行,开销小。
  2. 如果需要程序更加稳定安全时,可以选择进程。如果追求速度,就选择线程。

并发编程前言

单核处理器也支持多线程执行代码,CPU通过给每个线程分配CPU时间片来实现这个机制。时间片是CPU分配给各个线程的时间,因为时间片非常短(几十毫秒),CPU通过不停地切换线程执行,让我们感觉多个线程是同时执行的。

CPU通过时间片分配算法来循环执行任务

并发不一定比串行快,因为线程由创建上下文切换的开销

如何减少上下文切换

无锁并发编程

多线程竞争锁时,会引起上下文切换,所以多线程处理数据时,可以用一些办法来避免使用锁。比如数据的ID按照Hash算法取模分段,不同的线程处理不同段的数据。

CAS算法

Java的Atomic包使用CAS算法来更新数据,而不需要加锁。

使用最少线程

避免创建不需要的线程,比如任务很少,但是创建了很多线程来处理,这样会造成大量线程都处于等待状态。

协程

在单线程里实现多任务的调度,并在单线程里面维持多个任务间的切换。

死锁

定义

是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。

避免死锁的常见方法
  • 避免一个线程同时获取多个锁;
  • 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源;
  • 尝试使用定时锁,使用Lock.tryLock(timeout)来替代使用内部锁机制;
  • 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况;

Java并发机制的底层实现原理

待补充

Java内存模型

待补充

Java并发编程基础

待补充

Java中的锁

待补充

Java并发容器和框架

待补充

Java中的13个原子操作类

待补充

Java中的并发工具集

待补充

Java中的线程池

待补充

Executor框架

待补充

Java并发编程实践

待补充