自我成长 - thread
type: channel
link: https://yanxizhu.com/index.php/tag/thread/
items: ReentrantLock、StampedLock、ReentrantReadWriteLock、Condition
items: J.U.C之AQS
items: 线程安全-同步容器
items: 线程不安全的类与写法
items: 可见性和有序性
items: 线程八锁
items: ScheduledThreadPool线程调度
items: Executor线程池
items: ReadWriteLock读写锁
items: 线程按序交替

ReentrantLock、StampedLock、ReentrantReadWriteLock、Condition
type: item
date: 2022-04-25T16:07:45+00:00
description: 锁分为Synchronized和锁Lock。ReentrantLock与锁ReentrantLock(可重入锁)与Synchronized(同步锁)的区别：可重入性：区别不大，都是通过计数器，当计数器下降为0时，锁释放。锁的实现：Synchronized依赖JVM，ReentrantLock基于JDK实现。(类似Synchronized是操作系统实现，ReentrantLock是敲代码实现),ReentrantLock可通过看源码明白实现，Synchronized依赖JVM就看不到实现原理。性能的区别：优化之前Synchronized比ReentrantLock性能差很多，优化后Synchronized引入偏向锁、轻量级锁也就是自旋锁后，2者性能差不多了。差不多时，官方推荐Synchronized。功能的区别：Synchronized的使用方便简洁，隐式获取锁释放锁，ReentrantLock需要手动获取锁，释放锁，如果忘记容易出现死锁，所以最好再finally中释放锁。锁的颗粒度和灵活度很明显ReentrantLock优于Synchronized。ReentrantLock独有的功能：ReentrantLock可指定公平锁、非公平锁，而Synchronized只能时非公平锁。公平锁：先等待的先获取锁，反之亦然。提供了一个Condition类，可以分组唤醒需要唤醒的线程，Synchronized要么随机唤醒，要么全部唤醒。提供能够中断等待锁的线程的机制，lock.lockInterruptibly()，lockInterruptibly是一种自旋锁，通过循环来调用CAS来加锁，性能比较好，就是因为不会进入内核阻塞状态。使用场景：必须实现上面3个功能时，就必须用了。代码示例一ReentrantLock实现累加，注意与synchronized的不用用法package com.yanxizhu.demo.concurrency.lock; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @description: ReentrantLock锁实现计数，注意使用synchroized怎么实现的 * @author: 清风 * @date: 2022/4/25 23:09 * @version: 1.0 */ @Slf4j public class ReentrantLockDemo { //定义锁 private static Lock lock = new ReentrantLock(); //定义锁用户数 private static final int totalThread = 5000; //定义并发线程数 private static final int concurrentThread = 200; //定义总和 private static int count = 0; public static void main(String[] args) throws Exception{ //定义线程池 ExecutorService executorService = Executors.newCachedThreadPool(); //定义信号量 final Semaphore semaphore = new Semaphore(concurrentThread); //定义闭锁 final CountDownLatch countDownLatch = new CountDownLatch(totalThread); for (int i = 0; i < totalThread; i++) { executorService.execute(() -> { try { semaphore.acquire(); sum(); semaphore.release(); } catch (InterruptedException e) { log.error("错误信息:【{}】", e.getMessage()); } countDownLatch.countDown(); }); } …

J.U.C之AQS
type: item
date: 2022-04-25T14:47:12+00:00
description: AQSJ.U.C之AQS，底层由线程队列实现。AbstractQueuedSynchronizer简称AQS，JUC的核心。使用Node实现FIFO队列，可以用于构建锁或者其他同步装置的基础框架。利用了一个int类型表示状态。使用方法是继承。子类通过继承并通过实现它的方法管理其状态{acquire和release}的方法操纵状态。可以同时实现排它锁和共享锁模式（独占、共享）。AQS主要同步组件CountDownLatchSemaphoreCyclicBarrierReentrantLockConditionFutureTask依次介绍1、CountDownLatch-闭锁可以完成类似阻塞的功能。一个线程或多个线程等待，直到其它线程完成。使用场景，程序执行需要某个条件执行完后，才执行。示例一package com.yanxizhu.demo.concurrency.aqs; import com.yanxizhu.demo.concurrency.annotation.ThreadSafety; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * @description: CountDownLatch,实现线程阻塞，等待执行完再执行程序打印 * @author: 清风 * @date: 2022/4/25 20:24 * @version: 1.0 */ @Slf4j @ThreadSafety public class CountDownLatchDemo { private static final int threadNum = 500; public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); CountDownLatch countDownLatch = new CountDownLatch(threadNum); for (int i = 0; i <threadNum; i++) { final int num = i; executorService.execute(() -> { try{ pringNum(num); }catch (Exception e){ log.error("执行错误【{}】", e.getMessage()); }finally { countDownLatch.countDown(); } }); } countDownLatch.await(); executorService.shutdown(); log.info("finash .."); } public static void pringNum(int num) throws InterruptedException { Thread.sleep(100); log.info("num=【{}】", num); Thread.sleep(100); } }输出结果：。。。。。 20:36:34.598 [pool-1-thread-249] INFO com.yanxizhu.demo.concurrency.aqs.CountDownLatchDemo - num=【248】 20:36:34.608 [pool-1-thread-259] INFO com.yanxizhu.demo.concurrency.aqs.CountDownLatchDemo - num=【258】 20:36:34.597 [pool-1-thread-237] INFO com.yanxizhu.demo.concurrency.aqs.CountDownLatchDemo - num=【236】 20:36:34.597 [pool-1-thread-206] INFO com.yanxizhu.demo.concurrency.aqs.CountDownLatchDemo - num=【205】 20:36:34.608 [pool-1-thread-256] INFO com.yanxizhu.demo.concurrency.aqs.CountDownLatchDemo - num=【255】 20:36:34.608 [pool-1-…

线程安全-同步容器
type: item
date: 2022-04-24T04:21:00+00:00
description: 线程安全-同步容器主要包括ArrayList -> Vector，Stack HashMap->HashTable（key、value不能为null）Collections.synchronizedXXX（List、Set、Map）都是使用Synchronized进行修饰的，性能不是特别好。可以使用并发容器代替。注意：同步容器也可能是线程步安全的。同步容器线程步安全，代码示例：package com.yanxizhu.demo.concurrency.synContainer; import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety; import java.util.Vector; /** * @description: 同步容器，也可能出现线程不安全情况 * @author: 清风 * @date: 2022/4/24 10:32 * @version: 1.0 */ @UnThreadSafety public class DemoVecotNo { private static final Vector<Integer> vector = new Vector<>(); public static void main(String[] args) { //一直循环 while(true) { //向vector容器放入值 for(int i=0; i <10; i++){ vector.add(i); } //线程1，向vector容器移除值 new Thread(()->{ for(int i=0; i <vector.size(); i++){ vector.remove(i); } }).start(); //线程2，向vector中获取值 new Thread(()->{ for(int i=0; i <vector.size(); i++){ vector.get(i); } }).start(); } } }输出结果：Exception in thread "Thread-478" Exception in thread "Thread-1724" Exception in thread "Thread-1918" Exception in thread "Thread-1769" java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 10 at java.base/java.util.Vector.remove(Vector.java:875) at com.yanxizhu.demo.concurrency.synContainer.DemoVecotNo.lambda$main$0(DemoVecotNo.java:27) at java.base/java.lang.Thread.run(Thread.java:834) java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 62 at java.base/java.util.Vector.remove(Vector.java:875) at com.yanxizhu.demo.concurrency.synContainer.DemoVecotNo.lambda$main$0(DemoVecotNo.java:27) at java.base/java.lang.Thread.run(Thread.java:834) java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 2 at java.base/java.util.Vector.get(Vector.java:781) at com.yanxizhu.demo.concurrency.synContainer.DemoVecotNo.lambda$main$1(DemoVecotNo.java:34) at java.base/java.lang.Thread.run(Thread.java:834) java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 10 at java.base/java.util.Vector.remove(Vector.java:875) at com.yanxizhu.demo.concurrency.synContainer.DemoVecotNo.lambda$main…

线程不安全的类与写法
type: item
date: 2022-04-24T02:11:00+00:00
description: 线程不安全的类与写法线程不安全的类：类的对象可以同时被多个线程访问，比如抛出异常，逻辑错误。下面介绍一些常见的类。StringBuilderStringBuilder线程不安全的类代码示例package com.yanxizhu.demo.concurrency.threadUnSafetyClass; import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; /** * @description: 线程不安全的类：StringBuilder * @author: 清风 * @date: 2022/4/24 9:01 * @version: 1.0 */ @Slf4j @UnThreadSafety public class DemoStringBuilder { //用户数量 private static final int clientsTotal = 5000; //并发数量 private static final int concurrencyTotal = 200; //累加总和 private static StringBuilder stringBuilder = new StringBuilder(); public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); //信号量 final Semaphore semaphore = new Semaphore(concurrencyTotal); //闭锁 final CountDownLatch countDownLatch = new CountDownLatch(clientsTotal); for (int i = 0; i < clientsTotal; i++) { executorService.execute(()->{ try { semaphore.acquire(); update(); semaphore.release(); } catch (InterruptedException e) { log.error("出现错误:【{}】", e.getMessage()); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("字符长度Length=【{}】",stringBuilder.length()); } /** * 累加 */ private static void update(){ stringBuilder.append(1); } }每次输出字符长度不一样，也不等于5000StringBuffer线程安全的类代码示例package com.yanxizhu.demo.concurrency.threadUnSafetyClass; import com.yanxizhu.demo.concurrency.annotation.ThreadSafety; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; /** * @description: 线程安全的类：StringBuffer * @author: 清风 * @date: 2022/4/24 9:06 * @version: 1.0 */ @Slf4j @ThreadSafety public class DemoStringBuffer { //用户数量 private static final int cli…

可见性和有序性
type: item
date: 2022-04-21T13:39:00+00:00
description: 可见性可见性：一个线程对主内存的修改可以及时的被其它线程观察到。导致共享变量在线程间不可见的原因：线程交叉执行重排序结合线程交叉执行共享变量更新后的值没有在工作内存与主存间及时更新可见性-synchronizedJMM关于synchronized的两条规定：线程解锁前，必须把共享变量的最新值刷新到主内存线程加锁时，将清空工作内存中共享变量的值，从而使用共享变量时需要从主内存中重新读取最新的值（注意，加锁与解锁是同一把锁）可见性-volatilevolatile，通过加入内存屏障和禁止重排序优化来实现。对volatile变量写操作时，会在写操作后加入一条store屏障指令，将本地内存中的共享变量值刷新到主内存对volatile变量读操作时，会在读操作前加入一条load屏障指令，从主内存中读取共享变量volatile写：volatile读：有序性Java内存模型中，允许编译器和处理器对指令进行重排序，但是重排序过程不会影响到单线程程序的执行，却会影响到多线程并发执行的正确性.可通过volatile、synchronized、Lock保证有序性。有序性-happens-before原则程序次序规则：一个线程内，按照代码顺序，书写在前面的操作先行发生于书写在后面的操作锁定规则：一个unLock操作先行发生于后面对同一个锁的lock操作volatile变量规则：对一个变量的写操作先行发生于后面对这个变量的读操作传递规则：如果操作A先行发生于操作B，而操作B又先行发生于操作C，则可以得出操作A先行发生于操作C线程启动规则：Thread对象的start（）方法先行发生于此线程的每一个动作线程中断规则：对线程interrupt（）方法的调用先行发生于被中断线程的代码检测到中断事件的发生线程终结规则：线程中所有的操作都先行发生于线程的终止检测，我们可以通过Thread.join（）方法结束、Thread.isAlive（）的返回值手段检测到线程已经终止执行对象终结规则：一个对象的初始化完成先行发生于他的finalize（）方法的开始线程安全性-总结原子性：Atomic包、CAS算法、synchronized、Lock可见性：synchronized、volatile有序性：happens-before

线程八锁
type: item
date: 2022-03-19T14:57:58+00:00
description: 线程八锁package com.yanxizhu; /* * 题目：判断打印的 "one" or "two" ？ * * 1. 两个普通同步方法，两个线程，标准打印， 打印? //one two * 2. 新增 Thread.sleep() 给 getOne() ,打印? //one two * 3. 新增普通方法 getThree() , 打印? //three one two * 4. 两个普通同步方法，两个 Number 对象，打印? //two one * 5. 修改 getOne() 为静态同步方法，打印? //two one * 6. 修改两个方法均为静态同步方法，一个 Number 对象? //one two * 7. 一个静态同步方法，一个非静态同步方法，两个 Number 对象? //two one * 8. 两个静态同步方法，两个 Number 对象? //one two * * 线程八锁的关键： * ①非静态方法的锁默认为 this, 静态方法的锁为 对应的 Class 实例 * ②某一个时刻内，只能有一个线程持有锁，无论几个方法。 */ public class TestThread8Monitor { public static void main(String[] args) { Number number = new Number(); Number number2 = new Number(); new Thread(new Runnable() { @Override public void run() { number.getOne(); } }).start(); new Thread(new Runnable() { @Override public void run() { //number.getTwo(); number2.getTwo(); } }).start(); /*new Thread(new Runnable() { @Override public void run() { number.getThree(); } }).start();*/ } } class Number{ public static synchronized void getOne(){//Number.class try { Thread.sleep(3000); } catch (InterruptedException e) { } System.out.println("one"); } public synchronized void getTwo(){//this System.out.println("two"); } public void getThree(){ System.out.println("three"); } }一个对象里面如果有多个synchronized方法，某一个时刻内，只要一个线程去调用 其中的一个synchronized方法了，其它的线程都只能等待，换句话说，某一个时刻 内，只能有唯一一个线程去访问这些synchronized方法锁的是当前对象this，被锁定后，其它的线程都不能进入到当前对象的其它的 synchronized方法加个普通方法后发现和同步锁无关换成两个对象后，不是同一把锁了，情况立刻变化。都换成静态同步方法后，情况又变化所有的非静态同步方法用的都是同一把锁——实例对象本身，也就是说如果一个实 例对象的非静态同步方法获取锁后，该实例对象的其他非静态同步方法必须等待获 取锁的方法释放锁后才能获取锁，可是别的实例对象的非静态同步方法因为跟该实 例对象的非静态同步方法用的是不同的锁，所以毋须等待该实例对象已获取锁的非 静态同步方法释放锁就可以获取他们自己的锁。所有的静态同步方法用的也是同一把锁——类对象本身，这两把锁是两个不同的对 象，所以静态同步方法与非静态同步方法之间是不会有竞态条件的。但是一旦一个 静态同步方法获取锁后，其他的静态同步方法都必须等待该方法释放锁后才能获取 锁，而不管是同一个实例对象的静态同步方法之间，还是不同的实例对象的静态同 步方法之间，只要它们同一个类的实例对象！

ScheduledThreadPool线程调度
type: item
date: 2022-03-19T14:32:22+00:00
description: ScheduledThreadPool线程调度package com.yanxizhu; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /* * 一、线程池：提供了一个线程队列，队列中保存着所有等待状态的线程。避免了创建与销毁额外开销，提高了响应的速度。 * * 二、线程池的体系结构： * java.util.concurrent.Executor : 负责线程的使用与调度的根接口 * |--**ExecutorService 子接口: 线程池的主要接口 * |--ThreadPoolExecutor 线程池的实现类 * |--ScheduledExecutorService 子接口：负责线程的调度 * |--ScheduledThreadPoolExecutor ：继承 ThreadPoolExecutor， 实现 ScheduledExecutorService * * 三、工具类 : Executors * ExecutorService newFixedThreadPool() : 创建固定大小的线程池 * ExecutorService newCachedThreadPool() : 缓存线程池，线程池的数量不固定，可以根据需求自动的更改数量。 * ExecutorService newSingleThreadExecutor() : 创建单个线程池。线程池中只有一个线程 * * ScheduledExecutorService newScheduledThreadPool() : 创建固定大小的线程，可以延迟或定时的执行任务。 */ public class TestScheduledThreadPool { public static void main(String[] args) throws Exception { ScheduledExecutorService pool = Executors.newScheduledThreadPool(5); for (int i = 0; i < 5; i++) { Future<Integer> result = pool.schedule(new Callable<Integer>(){ @Override public Integer call() throws Exception { int num = new Random().nextInt(100);//生成随机数 System.out.println(Thread.currentThread().getName() + " : " + num); return num; } }, 1, TimeUnit.SECONDS); System.out.println(result.get()); } pool.shutdown(); } }

Executor线程池
type: item
date: 2022-03-19T14:23:00+00:00
description: Executors线程池package com.yanxizhu; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /* * 一、线程池：提供了一个线程队列，队列中保存着所有等待状态的线程。避免了创建与销毁额外开销，提高了响应的速度。 * * 二、线程池的体系结构： * java.util.concurrent.Executor : 负责线程的使用与调度的根接口 * |--**ExecutorService 子接口: 线程池的主要接口 * |--ThreadPoolExecutor 线程池的实现类 * |--ScheduledExecutorService 子接口：负责线程的调度 * |--ScheduledThreadPoolExecutor ：继承 ThreadPoolExecutor， 实现 ScheduledExecutorService * * 三、工具类 : Executors * ExecutorService newFixedThreadPool() : 创建固定大小的线程池 * ExecutorService newCachedThreadPool() : 缓存线程池，线程池的数量不固定，可以根据需求自动的更改数量。 * ExecutorService newSingleThreadExecutor() : 创建单个线程池。线程池中只有一个线程 * * ScheduledExecutorService newScheduledThreadPool() : 创建固定大小的线程，可以延迟或定时的执行任务。 */ public class TestThreadPool { public static void main(String[] args) throws Exception { //1. 创建线程池 ExecutorService pool = Executors.newFixedThreadPool(5); List<Future<Integer>> list = new ArrayList<>(); for (int i = 0; i < 10; i++) { Future<Integer> future = pool.submit(new Callable<Integer>(){ @Override public Integer call() throws Exception { int sum = 0; for (int i = 0; i <= 100; i++) { sum += i; } return sum; } }); list.add(future); } pool.shutdown(); for (Future<Integer> future : list) { System.out.println(future.get()); } /*ThreadPoolDemo tpd = new ThreadPoolDemo(); //2. 为线程池中的线程分配任务 for (int i = 0; i < 10; i++) { pool.submit(tpd); } //3. 关闭线程池 pool.shutdown();*/ } // new Thread(tpd).start(); // new Thread(tpd).start(); } class ThreadPoolDemo implements Runnable{ private int i = 0; @Override public void run() { while(i <= 100){ System.out.println(Thread.currentThread().getName() + " : " + i++); } } }

ReadWriteLock读写锁
type: item
date: 2022-03-19T07:36:00+00:00
description: 读写锁package com.yanxizhu; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @description: 读写锁(互斥锁) * @author: 清风 * @date: 2022/3/19 15:23 * @version: 1.0 */ public class ReadWriteDemo { public static void main(String[] args) { ReadWriteTest readWriteTest = new ReadWriteTest(); new Thread(()->{ readWriteTest.write((int) (Math.random()*101)); },"写锁").start(); for(int i=1;i<50;i++){ new Thread(()->{ readWriteTest.get(); },"读锁").start(); } } } class ReadWriteTest{ int num =0; private ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); //读 public void get(){ readWriteLock.readLock().lock(); try{ System.out.println(num+"=="+Thread.currentThread().getName()); }finally { readWriteLock.readLock().unlock(); } } //写 public void write(int i){ readWriteLock.writeLock().lock(); try{ this.num=i; }finally { readWriteLock.writeLock().unlock(); } } }

线程按序交替
type: item
date: 2022-03-19T07:11:14+00:00
description: 线程按序交替package com.yanxizhu; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @description: 线程按序交替 * @date: 2022/3/19 14:47 * @version: 1.0 */ public class PrintInfo { public static void main(String[] args) { print print = new print(); new Thread(new Runnable() { @Override public void run() { for(int i=1;i<5;i++){ try { print.printA(i); } catch (InterruptedException e) { e.printStackTrace(); } } } },"A").start(); new Thread(new Runnable() { @Override public void run() { for(int i=1;i<5;i++){ try { print.printB(i); } catch (InterruptedException e) { e.printStackTrace(); } } } },"B").start(); new Thread(new Runnable() { @Override public void run() { for(int i=1;i<5;i++){ try { print.printC(i); } catch (InterruptedException e) { e.printStackTrace(); } } } },"C").start(); } } class print{ private int num =1; Lock lock = new ReentrantLock(); Condition condition1 = lock.newCondition(); Condition condition2 = lock.newCondition(); Condition condition3 = lock.newCondition(); public void printA(int i) throws InterruptedException { lock.lock(); try{ if(num != 1){ condition1.await(); } System.out.println("A=="+Thread.currentThread().getName()+"====i="+i); num=2; condition2.signal(); }finally { lock.unlock(); } } public void printB(int i) throws InterruptedException { lock.lock(); try{ if(num != 2){ condition2.await(); } System.out.println("B=="+Thread.currentThread().getName()+"====i="+i); num=3; condition3.signal(); }finally { lock.unlock(); } } public void printC(int i) throws InterruptedException { lock.lock(); try{ if(num != 3){ condition3.await(); } System.out.println("C=="+Thread.currentThread().getName()+"====i="+i); num=1; condition1.signal(); }finally { lock.unlock(); } } }打印结果：A==A====i=1 B==B====i=1 C==C====i=1 A==A====i=2 B==B====i=2 C==C====i=2 A==A====i=3 B==B====i=3 C==C====i=3 A==A====i=4 B==B====i=4 C==C====i=4