
Java并发编程
文章平均质量分 70
Java并发编程的入门及深入,主要基于黑马满一航老师的课程提炼,相当于笔记以及自己的感悟
言葉长琴
这个作者很懒,什么都没留下…
展开
-
线程安全集合类概述
线程安全集合类可以分为三大类:遗留的线程安全集合如Hashtable,vector使用Collections装饰的线程安全集合Collections.synchronizedCollectionCollections.synchronizedListCollections.synchronizedMapCollections.synchronizedSetCollections.synchronizedNavigableMapCollections.synchronizedNaviga.原创 2022-05-16 01:03:39 · 465 阅读 · 0 评论 -
JUC-CyclicBarrier
循环栅栏,用来进行线程协作,等待线程满足某个计数,构造时设置【计数个数】,每个线程执行到某个需要“同步”的时刻调用await()方法等待,当等待的线程数满足【计数个数】时,继续执行CyclicBarrier barrier = new CyclicBarrier(2); new Thread(() -> { System.out.println("线程1开始" + new Date()); try { b原创 2022-05-16 00:54:10 · 171 阅读 · 0 评论 -
JUC-CountdownLatch
简介用来进行线程同步协作,等待所有线程完成倒计时。其中构造参数用来初始化等待计数值,await()用来等待计数归零,countDown()用来让计数减一public static void main(String[] args) throws InterruptedException { CountDownLatch latch = new CountDownLatch(3); new Thread(() -> { log.debug("b原创 2022-05-16 00:33:51 · 186 阅读 · 0 评论 -
JUC-Semaphore
基本使用信号量,用来限制能通知访问共享资源的线程上限public static void main(String[] args) { Semaphore semaphore = new Semaphore(3); for (int i = 0; i < 10; i++) { new Thread(() -> { try { semaphore.acquire();原创 2022-05-15 15:06:17 · 217 阅读 · 0 评论 -
JUC-StampedLock
该类自JDK8加入,是为了进一步优化读性能,他的特点是在使用读锁、写锁时都必须配合【戳】使用加解读锁long stamp = lock.readLock();lock.unlockRead(stamp);加解写锁long stamp = lock.writeLock();lock.unlockWrite(stamp);乐观读,StampedLock支持typeOptimisticRead()方法(乐观读),读取完毕之后需要做一次戳校验,如果校验通过,表示这期间确实没有写操作,数据可以安全使原创 2022-05-15 14:21:05 · 3558 阅读 · 0 评论 -
JUC-读写锁ReentrantReadWriteLock
1、ReentrantReadWriteLock当读操作远远高于写操作时,这时候使用读写锁让读-读可以并发,提高性能。类似于数据库中的select ... from ... lock in share mode提供一个数据容器类分别使用读锁保护数据的read()方法,写锁保护数据的write()方法public class DataContainer { private Object data; private ReentrantReadWriteLock rw = new Reen原创 2022-05-04 15:05:47 · 774 阅读 · 0 评论 -
JUC-ReentrantLock原理
1.原创 2022-05-04 01:03:06 · 362 阅读 · 0 评论 -
JUC-AQS(AbstractQueuedSynchronizer)原理
1、概述全称是AbstractQueueSynchronizer,是阻塞式锁和相关同步器工具的框架特点:用state属性来表示资源的状态(分独占模式和共享模式),子类需要定义如何维护这个状态,控制如何获取锁和释放锁getState - 获取state状态setState - 设置state状态compareAndSetState - cas机制设置state状态提供基于FIFO的等待队列,类似Monitor的EntryList条件变量来实现等待、唤醒机制,支持多个条件变量,类似Mon原创 2022-03-27 23:43:21 · 725 阅读 · 0 评论 -
7、共享模型之工具 - 3、Fork/Join
3、Fork/Join1)概念Fork/Join是JDK1.7加入的新的线程池实现,它体现的是一种分治思想,适用于能够进行任务拆分的CPU密集型运算所谓的任务拆分,是将一个大任务拆分为算法上相同的小任务,直至不能呢个拆分可以直接求解。跟递归相关的一些计算,如归并排序、斐波那契数列,都可以用分支思想进行求解Fork/Join在分支的思想上加入了多线程,可以把每个任务分解和合并交给不同的线程来完成,进一步提升了运算效率Fork/Join默认会创建与CPU核心大小相同的线程池2)使用提交给Fork/原创 2022-03-26 23:16:46 · 480 阅读 · 0 评论 -
7、共享模型之工具 - 2、ThreadPoolExecutor
2、ThreadPoolExecutor1)线程池状态ThreadPoolExecutor使用int的高3位表示线程池状态,低29位表示线程数量状态名高3位接收新任务处理阻塞队列任务说明RUNNING111YYSHUTDOWN000NY不会接收新任务,但会处理阻塞队列剩余任务STOP001NN会中断正在执行的任务,并抛弃阻塞队列任务TIDYING010--任务全部执行完毕,活动现场为0即进入终结TERMINATED0原创 2022-03-26 22:37:10 · 854 阅读 · 0 评论 -
7、共享模型之工具 - 1、自定义线程池
1、线程池1、自定义线程池步骤1:自定义拒绝策略@FunctionalInterfacepublic interface RejectPolicy<T> { void reject(BlockingQueue<T> queue, T task);}步骤2:自定义任务队列@Slf4j(topic = "c.BlockingQueue")public class BlockingQueue<T> { // 1.任务队列 priva原创 2022-03-23 01:44:52 · 139 阅读 · 0 评论 -
6、共享模型之不可变
本章内容不可变类的使用不可变类设计无状态类设计1、日期转换问题问题提出下面代码在运行时,由于SimpleDateFormat 不是线程安全的SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); for (int i = 0; i < 10; i++) { new Thread(() -> { try {原创 2022-03-13 02:00:53 · 166 阅读 · 0 评论 -
5、共享模式之无锁(下)
7、原子累加器累加器性能比较private static <T> void demo(Supplier<T> adderSupplier, Consumer<T> action) { T adder = adderSupplier.get(); List<Thread> threads = new ArrayList<>(); long start = System.nanoTime();原创 2022-03-12 16:21:06 · 375 阅读 · 0 评论 -
5、共享模式之无锁(上),CAS,原子类
本章内容CAS 与 volatile原子整数原子引用原子累加器Unsafe6.1、问题的提出有如下需求,保证accont.withdraw取款方法的线程安全public interface Account { // 获取余额 Integer getBalance(); // 取款 void withdraw(Integer amount); /** * 方法内启动1000个线程,那么每个线程做-10的操作 * 如果初始余额原创 2022-03-10 01:28:02 · 190 阅读 · 0 评论 -
4、Java内存模型、volatile原理、CPU缓存结构、balking模式、单例模式
本章内容上一章讲解的Monitor主要关注的是访问共享变量时,保证临界区代码的原子性这一张进一步深入学习共享变量在多线程之间的【可见性】问题与多条指令执行时的【有序性】问题1、Java内存模型JMM即Java Menory Model,它定义了主存,工作内存的抽象概念,底层对应着CPU寄存器、缓存、硬件内存、CPU指令优化等。JMM 体现在以下几个方面原子性 - 保证指令不会受到线程上下文切换的影响可进行 - 保证指令不会受到CPU缓存的影响有序性 - 保证指令不会受到CPU指令优化的影响原创 2022-03-08 21:58:03 · 263 阅读 · 0 评论 -
3、后记 - 同步模式之顺序控制 (控制线程操作顺序)
1、固定运行顺序比如,必须先2后1打印1.1、wait notify 版本static Object obj = new Object(); static boolean t2runed = false; public static void main(String[] args) { Thread t1 = new Thread(() -> { synchronized (obj) { while(!t2r原创 2022-03-07 01:22:30 · 165 阅读 · 0 评论 -
第三章小结
写在前面由于本章较长,所以按照小标题发布了本章小结分析多线程访问共享片段时,哪些代码片段属于临界区使用synchronized互斥解决临界区的线程安全问题掌握synchronized锁对象语法掌握synchronized加载成员方法和静态方法语法掌握wait/notify同步方法使用lock互斥解决代码临界区的线程安全问题掌握lock的使用细节:可打断、锁超时、公平锁、条件变量学会分析变量的线程安全性、掌握常见线程安全类的使用了解线程活跃性问题:死锁、活锁、饥饿应用方面原创 2022-03-07 01:21:51 · 91 阅读 · 0 评论 -
3.11、ReentrantLock
相对于synchronized它具备以下特点可中断可以设置超时时间可以设置为公平锁支持多个条件变量与synchronized一样,都支持可重入基本语法reentrantLock.lock();try{ // 临界区} finally { // 释放锁 reentrantLock.unlock();}可重入可重入是指同一个线程如果首次获得了这把锁,那么因为它是这把锁的拥有者,因此有权再次获得这把锁如果是不可冲入锁,那么第二次获得锁时,自己也会被锁挡住 static原创 2022-03-07 16:35:51 · 116 阅读 · 0 评论 -
3.10、活跃性、死锁、哲学家就餐、活锁、饥饿
死锁有这样的情况:一个线程需要同时获得多把锁,这时就容易发生死锁t1线程获得A对象锁,接下来想获取B对象的锁,t2线程获得B对象锁,接下来想要获取A对象锁例: Object A = new Object(); Object B = new Object(); new Thread(() -> { synchronized (A) { log.debug("lock A");原创 2022-03-06 22:06:49 · 360 阅读 · 0 评论 -
3.9、多把锁
多把不相干的锁一间屋子有两个功能:睡觉、学习,互不相干现在小南要学习,小女要睡觉,但如果只用一间屋子(一把锁)的话,那么并发度很低解决方法是准备多个房间(多个对象锁)例如@Slf4j(topic = "c.BigRoom")class BigRoom { public void sleep() { synchronized (this) { log.debug("sleep 2小时"); try {原创 2022-03-06 18:14:59 · 126 阅读 · 0 评论 -
3.8、重新理解线程转换状态
假设有线程 Thread t情况1 NEW–>RUNNABLE当调用t.start()方法时,由 NEW --> RUNNABLE情况2 RUNNABLE <–> WAITINGt线程用synchronized(obj)获取了对象锁后调用obj.wait() 方法时,t线程从RUNNABLE --> WAITING调用obj.notify(),obj.notifyAll(), t.interrupt()时竞争锁成功,t线程从WAITING --> .原创 2022-03-06 18:06:06 · 315 阅读 · 0 评论 -
3.7、Park Unpark
基本使用它们是LockSupport类中的方法// 暂停当前线程LockSupport.park();// 回复某个线程的运行LockSupport.unpark(暂停线程对象)先park再unparkpublic static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() -> { log.debug("start...");原创 2022-03-06 16:23:33 · 75 阅读 · 0 评论 -
3.6、wait notify join原理及应用,同步模式之保护性暂停,异步模式之生产者消费者
小故事 - 为什么要wait由于条件不满足,小南不能继续进行计算但小南如果一直占用着锁,其他人就得一直阻塞,效率太低于是老王单开了一键休息室(调用wait方法),让小南到休息室(WaitSet)等着去了,但这是锁释放开,其他人可以由老王随机安排进屋知道小M将烟送来,大叫一声【你的烟到了】(调用notify方法)小南于是可以离开休息室,重新进入竞争锁的队列原理Owner线程发现条件不满足,调用wait方法,即可进入WaitSet变为WAITING状态BLOCKED和WAITING原创 2022-03-06 15:58:43 · 108 阅读 · 0 评论 -
3.5、Monitor概念、synchronized原理、synchronized锁升级及实例(轻量级锁、重量级锁、自旋锁、偏向锁)
Monitor概念Java对象头以32位虚拟机为例普通对象数组对象其中Mark Word结构为64位虚拟机Mark Word参考资料https://stackoverflow.com/questions/26357186/what-is-in-java-object-header原理之Monitor(锁)Monitor被翻译为监视器或管程每个Java对象都可以关联一个Monitor对象,如果使用synchronized给对象上锁(重量级)之后,该对象头的Mark Work中原创 2022-03-06 03:13:22 · 509 阅读 · 0 评论 -
3.4、线程安全习题
习题卖票练习测试下面代码是否存在线程安全问题,并尝试改正package sync.test;import lombok.extern.slf4j.Slf4j;import java.util.ArrayList;import java.util.List;import java.util.Random;import java.util.Vector;/** * @author: 言叶长琴 */@Slf4j(topic = "c.ExerciseSell")public cla原创 2022-03-06 03:07:33 · 268 阅读 · 0 评论 -
3.3、变量的线程安全分析
变量的线程安全分析成员变量和静态变量是否线程安全?如果它们没有共享,则线程安全如果它们被共享了,根据它们的状态是否能够改变,又分两种情况如果只有读操作,则线程安全如果有读写操作,则这段代码是临界区,需要考虑线程安全局部变量是否线程安全局部变量是线程安全的单局部变量引用的对象则未必如果该对象没有逃离方法的作用访问,它是线程安全的如果该对象逃离方法的作用范围,需要考虑线程安全局部变量线程安全分析public static void test1() { int i =原创 2022-03-06 03:06:14 · 226 阅读 · 0 评论 -
3.2、synchronized关键字 解决竞争的方案
1、synchronized 解决方案为了避免领截取的竞态条件发生,有多种手段可以达到目的。阻塞时的解决方案:synchronized,Lock非阻塞式的解决方案:原子变量本次使用阻塞式的解决方案:synchronized,来解决上述问题,及俗称的【对象锁】,它采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】,其他线程想要获取这个【对象锁】时就会阻塞住。这样就能保证拥有锁的线程可以安全的执行临界区内的代码,不用担心线程的上下文切换注意虽然Java中互斥和同步都可以采用synchro原创 2022-03-06 03:04:02 · 547 阅读 · 0 评论 -
3、共享模型之管程 -- 3.1、共享带来的问题
1、共享带来的问题小故事老王(操作系统)有一个功能强大的算盘(CPU),现在想把它租出去,赚一点外快小南、小女(线程)来使用这个算盘进行一些计算,并按照时间给老王支付费用但小南不能一天24小事使用算盘,他经常要小憩一会儿(sleep),又或者是去吃饭上厕所(阻塞io操作),有时还需要一根烟,没烟的时候思绪全无(wait),这些情况称为阻塞在这些时候,算盘没有利用起来(不能收钱了),老王觉得有点不划算另外,小女也想用用算盘,如果总是让小南占着算盘,小女觉得不公平于是,老王灵机一动,想了个办原创 2022-03-06 03:01:27 · 345 阅读 · 0 评论 -
2、Java线程
1、创建和运行线程方法一、直接使用Thread // 直接使用Thread(继承/匿名内部类) Thread t1 = new Thread("t1") { @Override public void run() { log.debug("hello1"); } }; t1.start();方法二、使用Runnable配合Thread // 使用Runnable配合Thread(函数式接口)原创 2022-03-03 23:05:35 · 321 阅读 · 0 评论 -
1、进程与线程
1 进程与线程1.1 进程与线程进程程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至CPU,数据加载至内存。在指令运行的过程中还要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理IO的。当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程。进程就可以视为程序的一个实例。大部分程序可以同时运行多个实例进程(例如记事本、画图、浏览器等),也有的程序只能启动一个实例进程(例如网易云音乐、360安全卫士等)线程一个进程之内可以分为一到多个线程。原创 2022-02-27 21:58:56 · 128 阅读 · 0 评论