Java多线程与并发编程

graph LR;
并发-->线程安全
线程安全-->三大特性
线程安全-->volatile
并发-->锁
锁-->sychronized

1.线程安全

1.1概念

在拥有共享数据的多条线程并行执行的程序中,线程 安全的代码会通过同步机制保证各个线程都可以正常 且正确的执行,不会出现数据污染等意外情况。

1.2 线程安全三大特性

  • 原子性 :即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何 因素打断,要么就都不执行。i = i + 1。
  • 可见性 : 当多个线程访问同一个变量时,一个线程修改了这个变量的值,其 他线程能够立即看得到修改的值。
  • 有序性 : 如果在本线程内观察,所有的操作都是有序的;如果在一个线程观 察另一个线程,所有的操作都是无序的。

1.3 volatile关键字

可见性:对于加了volatile关键字的成员变量,在对这个变量进⾏修改时,会直接将CPU⾼级缓存中的数据写回到主内存,对这个变量的读取也会直接从主内存中读取,从⽽保证了可⻅性 ,也就是当㇐个线程修改了㇐个被 volatile修饰共享变量的值,新值总是可以被其他线程⽴即得知。

有序性 :底层是通过操作系统的内存屏障来实现的,由于使⽤了内存屏障,所以会禁⽌指令重排,所以同时也就保证 了有序性,在很多并发场景下,如果⽤好volatile关键字可以很好的提⾼执⾏效率。

(X)原子性:volatile无法保证原子性 对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不具 有原子性。

2.锁

2.1 sychronized(同步锁)

偏向锁:在锁对象的对象头中记录㇐下当前获取到该锁的线程ID,该线程下次如果⼜来获取该锁就可以直接 获取到了

轻量级锁:由偏向锁升级⽽来,当㇐个线程获取到锁后,此时这把锁是偏向锁,此时如果有第⼆个线程来竞 争锁,偏向锁就会升级为轻量级锁,之所以叫轻量级锁,是为了和重量级锁区分开来,轻量级锁底层是通过 ⾃旋来实现的,并不会阻塞线程

如果⾃旋次数过多仍然没有获取到锁,则会升级为重量级锁,重量级锁会导致线程阻塞

⾃旋锁:⾃旋锁就是线程在获取锁的过程中,不会去阻塞线程,也就⽆所谓唤醒线程,阻塞和唤醒这两个步 骤都是需要操作系统去进⾏的,⽐较消耗时间,⾃旋锁是线程通过CAS获取预期的㇐个标记,如果没有获取 到,则继续循环获取,如果获取到了则表示获取到了锁,这个过程线程㇐直在运⾏中,相对⽽⾔没有使⽤太 多的操作系统资源,⽐较轻量。

锁升级

graph LR;

偏向锁--第二个线程竞争锁-->轻量级锁
轻量级锁--自旋次数过多-->重量级锁

3.多线程

3.1 Java中创建线程的三种方式

  • 继承Thread类创建线程
  • 实现Runnable接口创建线程
  • 使用Callable和Future创建线程
继承Thread类 实现Runnable接口 利用线程池
优点 编程简单执行效率高 面向接口编程,执行效率高 容器管理线程,允许返回值与异常
缺点 单继承,无法对线程组有效控制 无法对线程组有效控制,没有返回值,异常 执行效率相对低,编程麻烦
使用场景 不推荐使用 简单的多线程程序 企业级应用,推荐使用

4.JVM内存模型