JUC用法-随笔01
一、概述
1.1、概念介绍
编写线程安全代码的核心:管理(共享、可变)状态的访问操作。
线程安全性:多线程访问某个类时,该类始终表现出正确的行为,则这个类是线程安全类。
无状态对象一定是线程安全的。
竞态条件:由不正确的执行顺序引发的不正确的结果。 常见的竞态条件:先检查、后执行。(根据一个可能失败的观测结果来决定下一步的动作),如:延迟初始化(在数据使用时初始化)
要保持状态的一致性,就必须在单个原子操作中更新所有相关的状态。
内置锁:同步代码块,用来支持原子性,由锁对象的引用、被锁保护的代码块组成,内置锁是一种互斥锁。
Java对象可以作为 内置锁(监视器),进入同步代码块之前获取锁,退出之前释放锁。
重入:某个线程可以成功获取已持有的锁。
重入的实现:
为每个锁关联一个计数值和一个线程,计数值为0表示锁没有被持有。 当线程请求一个没被持有的锁时,JVM记录下锁的持有者,并将计数值设置为1; 同一个线程再次获取该锁时,计数值加一,退出时减一,当计数值为0时,释放锁。
为什么多线程访问共享变量时,要上同一把锁:确保线程A写入的变量对其他线程可见。
volatile:可以禁止指令重排,用于同步共享数据。 volatile 可以保持程序执行的有序性、变量的可见性。 volatile 常用于while循环的条件
总结:
线程安全性:对象、方法、数据结构可以被多个线程访问而不会出现任何问题。
同步: 为避免多线程访问公共资源而导致数据不一致而采取的手段,使用同步机制可以确保在任何给定时间只有一个线程可以访问共享资源。
锁: 实现“同步”的具体手段。synchronized关键字、显示锁、读写锁等。
二、CountDownLatch 闭锁
1 import java.util.concurrent.CountDownLatch; 2 3 public class Main { 4 5 public static void main(String[] args) throws InterruptedException { 6 7 int taskNum = 5; 8 9 // 设置等待5个任务全部执行完毕才继续后面的操作 10 CountDownLatch latch = new CountDownLatch(taskNum); 11 12 // 开启5个任务 13 for (int i = 0; i < taskNum; i++) { 14 int idx = i; 15 new Thread(()->{ 16 System.out.println("任务"+idx+"正在执行"); 17 // 计数器减一,当计数器减到0时,继续执行main线程的代码 18 latch.countDown(); 19 }).start(); 20 } 21 22 // 主线程等待5个任务执行完毕 23 latch.await(); 24 25 System.out.println("5个任务执行完毕后的main函数代码"); 26 27 } 28 }
三、CyclicBarrier
1 public class Main { 2 3 public static void main(String[] args) throws InterruptedException { 4 5 int taskNum = 5; 6 7 CyclicBarrier barrier = new CyclicBarrier(taskNum,()->{System.out.println("全部任务已经就绪");}); 8 9 for(int i=0; i<taskNum; i++){ 10 int idx = i; 11 new Thread(()->{ 12 System.out.println("任务"+idx+"正在准备中"); 13 barrier.await(); 14 System.out.println("任务"+idx+"已经完成"); 15 }).start(); 16 17 } 18 19 } 20 }

浙公网安备 33010602011771号