多线程与并发
文章平均质量分 56
多线程与并发
程序员·小李
不知道要干什么的时候,停一停,想一想;知道想要什么的时候,努努力,拼一拼。
展开
-
Balk——你不来,我走了
它是在条件不满足时,阻塞等待一定的时长,如还不满足,则返回(抛出异常)。,例如在文本没有变动时的自动保存操作,文本没有变动,存是不会有数据问题的,但会带来性能问题。如果已经执行过初始化,条件不满足(不满足需要初始化的条件)则直接返回。通过synchronized关键字保护,判断一个契机,如果契机满足则继续执行,不满足则直接返回。当条件不满足时,Guarded Suspension选择自旋等待,而Balk选择直接返回。如果条件不满足时,不要等待条件再次成立,则采用balk比较合适,可以提供程序的响应性。原创 2022-09-21 07:09:59 · 156 阅读 · 0 评论 -
Guarded Suspension——你不来,我死等
LinkedBlockingQueue是线程安全的,在内部完成了加锁操作,提供了take和put方法。通过wait和notify机制,实现线程之间的协同,通过信号完成通信,同时执行的线程只有一个。4. putRequest的操作是创建并满足条件,通知另外的线程处理。一个线程put,一个get,当没有东西可以get时,就会阻塞。2. while循环在判断是否条件满足,不满足则循环等待。无需关注锁的获取与释放,wait和notify操作。3. 当条件满足时,跳出while,开始执行后续操作。原创 2022-09-20 08:41:17 · 75 阅读 · 0 评论 -
Immutable——我只读,我免疫!
因为虽然final可以保证引用不可修改,但如果本身就是一个对象,那么对象的内部状态不一定是不可变的,那就存在可变的风险,取而代之的方法是使用clone,复制一个实例出来。共享资源只会并发读取,不会写入。资源的状态(实例变量)不会发生修改,因此本身就是线程安全的。1. 类是final的,不可被继承(防止子类修改)3. 字段是final的,一旦赋值不可重复赋值。1. 避免直接使用外部的示例直接赋值给成员变量。2. 字段是private,外部不可直接读写。2. 避免直接将内部不可变实例传递给外部。原创 2022-09-20 07:36:25 · 83 阅读 · 0 评论 -
Single Threaded Execution——独木桥
多个线程同时访问共享资源时,需要使用synchronized隔离。如果线程之间操作的数据互不影响,也不需要考虑。只有多线程模式下才需要使用synchronized实现隔离,单线程程序无需考虑竞争问题。要注意被保护资源之间是否存在关联关系,例如A和B的读写是否存在原子性,是否同时读写。当共享资源的状态(可以理解为成员变量)不会发生任何改变时,无需考虑线程安全问题。通过加锁的方式,使得只有一个线程才可以进入临界区,保证数据的原子读写操作。必须考虑所有读写共享资源的位置,防止考虑不周全导致某些位置无法得到保护。原创 2022-09-20 07:10:50 · 166 阅读 · 0 评论 -
【AtomicIntegerArray】常规用法
对应AtomicInteger,AtomicIntegerArray用于操作整型数组。原创 2022-08-11 08:10:49 · 202 阅读 · 0 评论 -
【AtomicReference、AtomicStampedReference】常规用法
AtomicReference可以针对引用类型进行原子操作。原创 2022-08-11 07:37:52 · 792 阅读 · 0 评论 -
【AtomicLong】常规用法
无参构造,相当于AutomicLong(0L)有参构造,初始化为initValue类比AtomicInteger:getAndIncrement先返回现值,后自增1incrementAndGet先自增1,后返回值类比AtomicInteger:getAndDecrement先返回现值,后自减1decrementAndGet先自减1,后返回值public boolean compareAndSet(long source, long dest):source是改之前的值,Dest是改之后的值,source与当原创 2022-08-10 23:52:18 · 1754 阅读 · 0 评论 -
【AtomicBoolean】CAS并发控制
这里有一个AtomicBoolean用于存储true和false两种状态,true表示被占用,false表示空闲,当tryLock时,只有抢占到锁的那个线程的threadLocal变量才会存储true。当资源释放时,先判断当前线程是否抢占锁成功,如果threadLocal中存储true,说明当前线程正在持有锁,此时可以放心地修改当前线程的标记,并执行compareAndSet方法,将True改为False,锁释放。我们来看看AtomicBoolean怎么实现CAS并发控制。...原创 2022-08-10 23:20:39 · 264 阅读 · 0 评论 -
【AtomicBoolean】常规用法
AtomicBoolean也是juc包下的多线程安全的并发布尔型操作字段,底层实现依然是CAS。原创 2022-08-10 08:57:16 · 420 阅读 · 0 评论 -
【AtomicInteger】常规用法
众所周知,AtomicInteger用于多线程下线程安全的数据读写操作,避免使用锁同步,底层采用CAS实现,内部的存储值使用volatile修饰,因此多线程之间是修改可见的。原创 2022-08-09 08:03:02 · 11660 阅读 · 1 评论 -
CountDownLatch的用法
CountDownLatch就是个计数器,用于这样的场景:1. 存在主任务和子任务的场景。2. 主任务需要等待子任务的退出,不管是正常完成还是异常退出。3. 主任务在子任务尚未结束时,阻塞等待。所有子任务完成后,主任务恢复执行。4. 同时,CountDownLatch也支持设置阻塞等待时间,也就是说,为了避免出现僵尸子任务,如果主任务在等待指定时间后,仍然有子任务尚未退出,则不再等待,直接恢复。...原创 2022-06-16 22:55:52 · 691 阅读 · 0 评论 -
带MDC传递的ThreadPool实现
public class MDCThreadPoolTaskExecutor extends ThreadPoolTaskExecutor { /** * 带logId的线程执行方法 * @param task */ @Override public void execute(Runnable task) { ThreadPoolExecutor executor = this.getThreadPoolExecutor(); .原创 2022-04-29 11:39:08 · 1178 阅读 · 0 评论 -
一个自动释放上下文的ThreadPool实现
public class AutoClearThreadPoolExecutor<T> extends ThreadPoolExecutor { private ThreadLocal<T> localData = new ThreadLocal<>(); public T data() { return localData.get(); } private void init(T data) { l.原创 2022-04-29 11:36:00 · 192 阅读 · 0 评论 -
CopyOnWriteArrayList写时复制
写时复制的原理所有的读,均直接从数组中获取数据。所有的写,通过先复制数组得到副本,修改副本,然后重新指向新数组的步骤。适用于“读多写少”的场景。写时复制的缺点CopyOnWriteArrayList每次执行写操作都会将原容器进行拷贝一份,数据量大的时候,内存会存在较大的压力,可能会引起频繁Full GC。写和读分别作用在不同新老容器上,在写操作执行过程中,读不会阻塞,但读取到的却是老容器的数据。(不是最新的数据,相当于快照)写时复制的实现新增元素:public bo原创 2022-04-25 17:28:48 · 477 阅读 · 0 评论 -
ThreadPoolExecutor的使用
为何使用线程池1. 复用线程,减少线程创建和销毁带来的开销2. 主动控制线程数量,完成并发控制3. 简化对线程的管理难度可以不用线程池吗?可以,对于简单的多线程任务可直接new Thread处理。如果不使用线程池,还想减少开销的话,需要自行管理线程。四个常用构造器public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,原创 2022-04-25 15:08:27 · 2928 阅读 · 0 评论 -
Future与FutureTask
相同:Future和FutureTask的使用均是在ExecuteService基础上进行的。二者均支持返回值。二者均支持任务取消。不同:Future和FutureTask的对象来源不同。Future和FutureTask的提交方式不同。ExecutorService executorService = Executors.newCachedThreadPool();Future<Integer> future = executorService.submit原创 2021-12-15 15:49:23 · 845 阅读 · 0 评论 -
全局线程异常处理
1. 线程的线程异常处理器package com.jdojo.threads;public class CatchAllThreadExceptionHandler implements Thread.UncaughtExceptionHandler { public void uncaughtException(Thread t, Throwable e) { System.out.println("Caught Exception from Thread:"原创 2021-05-27 16:20:53 · 225 阅读 · 0 评论 -
synchronize与volatile
synchronize同步代码块做了啥?同步代码块在获取锁后,首先从主内存中同步最新的数据到线程本地的工作内存中,在释放锁之前,将本地工作内存中的最新数据同步写入主内存中。有没有其他方式直接读写主内存?有,volatile变量,适用于多线程环境中公共资源的共享,性能比同步代码块更高,效率更快,代价更低1. 对volatile变量的读取数据,是直接在主内存中获取的。2. 对volatile变量的写入,是直接写入到主内存中的。3. 线程的本地工作内存是不保存副本的。4. 对于数.原创 2021-05-27 16:15:16 · 141 阅读 · 0 评论 -
线程组的概念
主线程&主线程组主线程的名字是main,线程组为main主线程内创建的子线程,默认所在的组是主线程所在的组。package com.jdojo.threads;public class DefaultThreadGroup { public static void main(String[] args) { // Get the current thread, which is called "main" Threa原创 2021-05-27 15:27:22 · 238 阅读 · 0 评论 -
Java多线程的中断
运行中的中断1. 使用Thread.interrupted() // no System.out.println(Thread.interrupted()); // interrupt Thread mainThread = Thread.currentThread(); mainThread.interrupt(); // yes and clear System.out.print原创 2021-05-27 15:11:44 · 169 阅读 · 0 评论 -
生产者和消费者的Java多线程实现(改造版)
队列的设计public class Buffer<T> { private T[] data; private int size; private boolean empty; private int reader; private int writer; public boolean isEmpty() { return reader == writer; } public boolean isFull原创 2021-05-27 12:04:24 · 120 阅读 · 0 评论 -
生产者和消费者的Java多线程实现
实现目标我们设定一定空间的队列,由生产者进行生产(填充队列)和消费者进行消费(取队列数据)。生产者在队列满的时候需要等待,消费者在队列空的时候需要等待。同时保证多个生产者、消费者的线程安全和数据协同。队列的设计public class Buffer<T> { private T[] data; private int size; private boolean empty; private int reader; private in.原创 2021-05-27 10:33:17 · 407 阅读 · 0 评论 -
线程同步
多线程之间的临界区域问题在多线程问题中,我们提到,当对共享资源进行同时读写的时候很可能造成多线程下的非预期的结果,因为多个线程之间的指令执行顺序是乱序的,难免balance值是110的时候读取,然后退出了程序。如果update和monitor方法只能执行一个,则会解决此问题,也就是线程同步。1. 互斥锁同步。在前面所说的多线程问题中可以采用这种方式解决。2. 条件同步。生产者消费者场景下的条件同步问题在多线程下的生产者和消费者的案例,一个线程生产数据到缓存区,一个线程从缓存区获...原创 2021-05-26 17:05:46 · 128 阅读 · 0 评论 -
Java内存模型(JMM)
Java内存模型java中,实例变量、静态变量、数组,都是分配到主内存的。各个线程都有自己独立的内存空间,通常是处理器缓存或者寄存器空间,线程之间是不能访问彼此的独立内存空间的。线程之间是共享主内存空间的,线程内存都有独立的栈,用于存储局部变量。假如某个进程开启了两个线程,分别在不同的处理器上执行。此时,线程1操作了Object1对象,并更新的它的值,但是没有同步到主内存中,此时线程2读取到Object1对象的值是更新前的旧值么?假如,线程1操作了Object1对象,并更新的它的值,原创 2021-05-26 11:35:25 · 64 阅读 · 0 评论 -
多线程问题
多线程的使用示例package com.jdojo.threads;public class MultiPrinterThread { public static void main(String[] args) { // Create two Thread objects Thread t1 = new Thread(MultiPrinterThread::print); Thread t2 = new原创 2021-05-26 10:48:37 · 189 阅读 · 0 评论 -
线程创建
线程创建线程创建需要两步:1. 创建Thread对象2. 执行start方法package com.jdojo.threads;public class SimplestThread { public static void main(String[] args) { // 1. Creates a thread object Thread simplestThread = new Thread();原创 2021-05-25 22:18:40 · 102 阅读 · 0 评论 -
单核与多核之争
单核不可能实现真正意义的多任务这里所说的多任务指的是,多个任务在同一时刻,一起执行。这个一起,指的是都在running。多进程之间通过抢占时间片的方式获取cpu资源,单核只有一个处理器,因此,在时间维度上,同一时间只能有一个进程在执行。单核给用户在感受上有多个程序在执行,实际上是在多个进程之间来回切换,由于时间片分配的单位很小,因此一般人无法感知到。但实际上,在时间维度上,同一时间只有一个进程在执行。多核多任务单个处理器上可以同时执行一个进程,那么多核就可以各自执行一个进..原创 2021-05-25 21:50:41 · 911 阅读 · 0 评论 -
Java多线程与并发06: 同步器
倒计时发射器CounterDownLatch很形象的可以翻译为倒计时发射器,代表的是等待计数器扣减为0的时候,继续执行下面的代码。否则将继续等待。1. 我们可以通过构造器传递一个初始计数:CountDownLatch(int count)2. 死等。 void await() 除非线程异常退出,直到countdown计数器为0返回。 3. 等你一段时间,不到0我就继续了。 boolean await(long timeout, TimeUnit ...原创 2021-02-05 16:17:22 · 169 阅读 · 0 评论 -
线程安全类的设计原则
《代码大全》就有提过,问题解决得越早,花费的代价就越小。首先考虑该类是否会存在于多线程环境。如果不是,则不考虑线程安全。然后考虑该类是否能设计为不可变对象,或者事实不可变对象。如果是,则不考虑线程安全最后,根据流程来设计线程安全类: 1、找出构成对象状态的所有变量。 2、找出约束状态变量的不变性条件。 3、建立对象状态的并发访问管理策略: a.java监视器模式。 一直使用某一对象的锁来保护某状态。...转载 2020-09-23 10:34:15 · 257 阅读 · 1 评论 -
Java多线程与并发05: 执行器
使用Executor使用executor可以实现类似与Thread的方法开辟线程:使用execute方法执行一个Runnable接口的实现。但是存在很多限制:1. 无法获取返回值2. 无法知道运行的进度,无法取消任务。3. 无法执行批量的任务。4. 无法终止线程。ExecutorServiceboolean awaitTermination(longtimeout, TimeUnit unit)等待线程完成,当调用shutdown或超时时间到了或被...原创 2020-08-09 17:32:00 · 279 阅读 · 2 评论 -
Java多线程与并发04: 线程安全的变量&定时器、定时任务
非捕获异常的处理当线程中抛出异常的时候,一般抛出并打印stacktrace:抛出异常:我们可以自定义未捕获异常处理器:当出现未捕获异常,会按照定义的UncaughtExceptionHandler去处理异常。当然,也可以为其设置默认的未捕获异常处理器,一般设置过未捕获异常处理器后,默认的处理器将被覆盖。ThreadLocal我们有这样的一个场景,需要将一些数据与线程绑定,例如用户id。我们可以使用局部变量,但是维护起来比较麻烦。我们也可以使...原创 2020-08-08 17:20:35 · 387 阅读 · 0 评论 -
Java多线程与并发03: 线程间的协同
多线程的协同多个线程之间协同使用共享资源的问题,对资源的读写进行条件控制,使用wait和notify方式控制线程之间的等待和唤醒操作。object类提供的apiwait方法:当前线程等待某个条件的成立,其他线程可以使用notify或notifyall方法唤醒当前线程。wait(long timeout)方法:与上面类似,但是有个超时时间,不会一直waitnotify()随机唤醒一个等待中的线程。notifyAll()唤醒所有,谁抢到锁是谁的。基本使用格式:...原创 2020-08-07 19:24:21 · 215 阅读 · 0 评论 -
Java多线程与并发02: 线程同步
多线程存在的问题使用多线程可以提高效率,但是会带来其他问题,例如数据共享时出现的混乱问题。都有哪些问题呢?1. 竞争条件a. 我们考虑这样的代码(check + act)当我们在单线程程序中运行时,没有任何问题。a和b都是局部变量的时候,也都没有问题。(因为每个线程都会保存一份副本)我们考虑这样的情形,a和b是成员变量或者静态成员变量,两个线程都来执行这段代码。假设,线程1执行完判断语句,即将执行赋值语句,好了时间片结束了。这个时候,另一个线程把a的值给改了,当线程.原创 2020-08-07 16:35:25 · 199 阅读 · 0 评论 -
Java多线程与并发01: 多线程基础
通过Runnable创建线程可以通过匿名内部类创建接口实例:也可以使用lambda表达式:然后传入Thread的构造器,构造线程:继承Thread类创建线程继承Thread,重写run方法,注意,没有输入参数,也没有返回值。线程的名称可以通过构造器,传入线程的名称,然后通过getName()获取名称也可以使用setName()设置名称线程的状态判断是否存在:线程的状态:枚举 含义 ......原创 2020-08-06 15:20:29 · 222 阅读 · 0 评论