Java并发编程
多线程编程
绅士jiejie
理想的生活,就是生活的理想!
展开
-
多线程查询结果,添加List集合
多线程查询结果,添加List集合原创 2022-08-04 23:35:37 · 1206 阅读 · 0 评论 -
Returned object not currently part of this pool
Returned object not currently part of this pool原创 2022-08-04 23:20:14 · 1885 阅读 · 0 评论 -
什么叫做happens-before关系
这里分享一个简单又通俗的理解,happens-before关系强调的其实是时间关系的一致性,它要求如果事件A应该在时间B之前发生,那么观察到的结果也应该这样,如果转换成代码方面的逻辑来说,就是如果变量的写发生在读之前,那么我们真正观察到的结果,也应该是写在读之前发生。...原创 2021-11-18 22:25:23 · 338 阅读 · 0 评论 -
更好的理解一下指令重排
对于指令重排,简单来说就是CPU会重排指令来尽可能的优化效率,可能会导致最终的运行结果和我们代码实际要的结果不一致,那接下来用更实际的例子来描述下指令重排,方便理解。假设有一段代码逻辑对应的CPU指令如下: //读取a的值赋值给r1 read(a) ->r1; //读取b的值赋值给r2 read(b) ->r2; r1+1; r2+1; 假设以上步骤,在指令读取a的值时,cpu缓存中没有值,那就得到内存里读取了,相反的,要读取的b值刚好在缓存中,那么读取到b值的速度就会比读取原创 2021-11-18 22:19:56 · 327 阅读 · 0 评论 -
乐观锁和悲观锁适用情况
悲观锁多用于”写多读少“的环境,这样可以避免因为频繁失败和重试影响性能。乐观锁多用于“读多写少“的环境,这样避免了频繁的加锁,提高性能。原创 2021-03-03 21:51:00 · 204 阅读 · 1 评论 -
程序计数器中保存的指令位置到底是哪一种?
看了好几篇文章,有的说程序计数器中存的值为正在执行的指令的位置,有的说是下一个将要被执行的指令的位置,其实二者的说法都没错,也没必要去混淆自己的记忆,因为程序计数器中存的值到底是正在执行的指令的位置还是下一个将要被执行的指令的位置,这个的具体实现其实是依赖于特定的系统的。...原创 2021-03-02 20:46:59 · 1514 阅读 · 0 评论 -
CPU缓存和内存间交换数据的单位
CPU缓存和内存间交换数据的单位就是缓存行,当线程要访问的变量在CPU的缓存里没有找到时,就会去访问主内存,然后根据程序运行的局部性原理,此时就会把主内存中该变量所在的大小为缓存行的内存放入缓存中。...原创 2021-01-22 21:15:35 · 2490 阅读 · 0 评论 -
volatile保证有序性的简单理解
使用volatile关键字修饰变量,写变量时,可以确保volatile写之前的操作不会被编译器重排序到volatile写之后,这样就保证了写之前的操作是完整的,这样修改出来的变量值才是正确的,而读变量时,确保读变量后的操作不会被编译器重排序到volatile读之前,避免后续的操作影响到读出的变量该有的正确值。...原创 2021-01-22 21:04:37 · 437 阅读 · 0 评论 -
什么时候才使用volatile关键字?
相比起synchronized关键字,volatile关键字也是能够解决共享变量的内存可见性问题,而且还是非阻塞的,性能也要比synchronized关键字要好,因为synchronized关键字是独占锁,一个线程获取到锁后,其他线程就只能阻塞了,这就会产生线程的上下文切换和重新调度的开销,那为什么volatile关键字没法替代synchronized关键字,因为volatile关键字没法保证操作的原子性。那么在什么情况下,可以使用volatile关键字替换synchronized关键字来提高性能?原创 2021-01-22 20:56:42 · 893 阅读 · 0 评论 -
了解下synchronized的内存语义
进入synchronized块的内存语义,是把在synchronized块内使用到的变量从线程的本地工作内存中清除,这样要获取该变量的就只能去主内存里拿了,而退出synchronized块的内存语义,是把在synchronized块内对共享变量的修改刷新到主内存,这样一来一回,再加上synchronized关键字内置的监视器锁效果,共享变量的内存可见性问题也就解决了。...原创 2021-01-22 20:39:23 · 303 阅读 · 0 评论 -
java内置的锁被叫做什么?
java内置的那些使用者看不到的锁,被称为内部锁,也被叫做监视器锁,像synchronized关键字用的就是监视器锁。原创 2021-01-22 20:30:18 · 188 阅读 · 0 评论 -
了解下线程上下文切换的时机
当前线程的CPU时间片使用完,然后处于就绪状态时。当前线程被其他线程中断时。原创 2021-01-20 22:12:08 · 795 阅读 · 0 评论 -
JMM模型是规范
只要学到并发编程,那么就肯定绕不过JMM模型,很多知识点,结合这个模型,理解起来会更容易,刚好看到有这么一句描述JMM模型的话:该模型就是一套规范,对上,是JVM和开发者之间的协定,对下,是JVM和编译器以及CPU之间的协定。以上就是简单的分享一下,感觉有利于加深对JMM的理解。...原创 2020-12-11 20:20:58 · 245 阅读 · 0 评论 -
了解下重排序的分类
编译器重排序:如果语句没有先后依赖关系,那么为了优化性能,编译器可以重新调整语句的执行顺序。CPU指令重排序:在指令级别,让没有依赖关系的多条指令并行执行。CPU内存重排序:CPU有自己的缓存,指令的执行顺序和写入主内存的顺序没有完全一致。...原创 2020-12-11 19:49:46 · 561 阅读 · 0 评论 -
轻量级阻塞和重量级阻塞
轻量级阻塞:能够被中断的阻塞被成为轻量级阻塞,对应的线程状态是waiting和timed_waiting。重量级阻塞:不能够被中断的阻塞被成为重量级阻塞,对应的线程状态是blocked。原创 2020-12-11 19:39:21 · 230 阅读 · 0 评论 -
join方法为什么可以做到等待的效果?
以下是join的源码:public final synchronized void join(long millis)throws InterruptedException { //获取当前时间 long base = System.currentTimeMillis(); //用来和join的超时时间做比较,先默认为0 long now = 0; //参数判断,小于0则抛出异常 if (millis < 0) { throw new原创 2020-08-13 20:58:00 · 309 阅读 · 0 评论 -
线程组内的某个线程出现异常,如何停止其他的线程运行?
首先自定义一个遇到异常可以有中断能力的线程组,如下:package com.example.springboot.codedemo;public class MyThreadGroup extends ThreadGroup { public MyThreadGroup(String name) { super(name); } @Override public void uncaughtException(Thread t, Throwable e原创 2020-08-05 18:58:09 · 2006 阅读 · 0 评论 -
同一线程组下的线程,一个线程的异常会影响其他线程运行么?
测试demo:public class Test { static class MyThread extends Thread { private String number; public MyThread(ThreadGroup group, String name, String number) { super(group, name); this.number = number; }原创 2020-08-05 18:40:52 · 3099 阅读 · 1 评论 -
在缓存设计时,需要遵循哪些原则?
在数据写入时,先写数据库,再写缓存在读取数据时,先读缓存,如果缓存不存在,再读数据库,同时将数据写入缓存中在更新数据时,先删除缓存,再更新数据,最后再把新数据写入缓存在删除数据时,先删除缓存,再删除数据库中的数据...原创 2020-08-04 12:09:20 · 496 阅读 · 0 评论 -
简单理解什么是非阻塞异步编程方法
非阻塞异步编程方法使用一个监听器,在使用回调的过程中,能够自动感知到调用结果,从而实现高并发的调用方法,简单的理解就是,使用了非阻塞异步编程方法,可以让我们在发起一个回调方法后,配合上一个自动监听机制,在回调方法执行完成后,主动且及时的通知调用者,这样就实现了一个非阻塞的回调方法了。...原创 2020-08-04 12:08:31 · 322 阅读 · 0 评论 -
通过线程组实现批量停止线程
代码demo:import java.util.concurrent.TimeUnit;public class StopMuchThread { static class MyThread extends Thread { private ThreadGroup group; private String name; public MyThread(ThreadGroup group, String name) {原创 2020-08-03 12:09:24 · 396 阅读 · 0 评论 -
怎么让线程运行具有有序性
多线程运行,基于CPU的时间片调度机制,线程运行的情况也会不同,优先级也不能够做到控制线程之间的运行顺序,所以如果需要让几个线程间有序的执行,需要根据运行的规则,自己定义一个线程类。代码demo:public class SortThread extends Thread { //锁 private Object lock; //要打印的字母 private String printChar; //需要打印字母的顺序所对应的取余值 private int原创 2020-08-03 12:08:22 · 767 阅读 · 0 评论 -
为什么说++value不是原子性的操作
demo:public class CountTest { private int value; public void add() { ++value; }}使用javac编译CountTest.Java文件javac CountTest.java 获得CountTest.class文件。再使用javap -c命令反编译CountTest.class文件javap -c CountTest.class看看它的汇编代码,如下:从汇编代码中可原创 2020-08-03 12:07:10 · 328 阅读 · 0 评论 -
为什么ForkJoinPool可以创建出类型为ForkJoinWorkerThread的线程?
直接看下ForkJoinPool的无参构造方法,如下:ForkJoinPool forkJoinPool = new ForkJoinPool();跟进构造方法源码中,如下:public static final ForkJoinWorkerThreadFactory defaultForkJoinWorkerThreadFactory;public ForkJoinPool() { this(Math.min(MAX_CAP, Runtime.getRuntime().ava原创 2020-07-27 12:17:04 · 728 阅读 · 0 评论 -
ForkJoinPool的fork()方法做了什么事?
先看看fork()方法的源码,如下:public final ForkJoinTask<V> fork() { //定义一个线程实例属性t Thread t; //取得当前线程实例赋值给t,然后判断该线程是否是ForkJoinWorkerThread类型 if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) //如果是,则把该任务加入到当前线程的工作队列中原创 2020-07-27 12:12:32 · 544 阅读 · 0 评论 -
抽象了解下ForkJoinTask的拆分思想
demo代码如下:import java.util.concurrent.ForkJoinPool;import java.util.concurrent.ForkJoinTask;import java.util.concurrent.RecursiveTask;import java.util.concurrent.atomic.AtomicInteger;public class TestForkJoinPool { static class ForkJoinSumCalculat原创 2020-07-25 21:46:39 · 278 阅读 · 0 评论 -
JMM中的工作内存和主内存对应着JVM运行时数据区的哪些部分
工作内存是私有区域,所以工作内存可以对应着JVM运行时数据区的线程私有部分,包括虚拟机栈,本地方法栈,程序计数器。主内存是共享区域,所以主内存可以对应着JVM运行时数据区的线程共享部分,包括堆和方法区。...原创 2020-07-24 19:21:50 · 670 阅读 · 0 评论 -
如何让子线程获取到父线程的ThreadLocal中的值
代码demo如下:public static void main(String[] args) throws InterruptedException { Thread parentParent = new Thread(new Runnable() { @Override public void run() { ThreadLocal threadLocal = new ThreadLocal(); threadLo原创 2020-07-24 12:40:52 · 2577 阅读 · 0 评论 -
使用线程组统一处理异常
使用线程组统一处理异常代码demo:public static void main(String[] args) { ThreadGroup threadGroup = new ThreadGroup("线程组一") { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println(t.getName() + e.getMessage()原创 2020-07-24 12:10:59 · 217 阅读 · 0 评论 -
为什么说Java8的Stream并行流底层使用了Fork/Join框架
先写一个Java8Stream并行流的demo,如下:import java.util.stream.Stream;public class AtomicIntegerArrayTest { public static void main(String[] args) { Stream.of(1, 2, 3, 4, 5).parallel().reduce((a, b) -> { return a + b; }).ifPresent原创 2020-07-23 22:53:13 · 974 阅读 · 2 评论 -
多进程也可以实现并发,为什么还要使用多线程?
一般使用多进程或者多线程都会涉及到共享资源,那么多进程或者多线程之间就要进行通信,保证数据的安全和准确,而进程间的通信要比线程间的通信复杂许多。进程是重量级的,而线程是轻量级的,因此多线程方式的系统开销会小很多。...原创 2020-07-23 12:11:22 · 1022 阅读 · 0 评论 -
线程上下文切换的上下文指的是什么?
某一时间点CPU寄存器和程序计数器的内容,被称为上下文。寄存器是CPU内部的少量速度很快的闪存。程序计数器是一个专用的寄存器,被用来表示指令序列中CPU正在执行的位置。原创 2020-07-23 12:10:48 · 1997 阅读 · 0 评论 -
内部锁的使用一定会导致上下文的切换?
如果一个线程申请一个锁时,该锁正被另一个线程所持有,那么这个线程可以进入等待状态,等待持有锁的线程释放锁,然后再去和其他线程一起竞争锁,不过这样的方法会导致线程的上下文切换,或者该线程采用忙等的方法,无限循环空操作,直到所需的条件达成,CAS就是这思想的具体实现,所以内部锁的使用不一定会导致线程的上下文切换,同时Java虚拟机也加入了适应性锁的方案,在JIT编译器的帮助下,对于一个具体的锁实例,Java虚拟机会根据其运行过程中收集到的信息来判断这个锁被线程持有的时间是长还是短,如果是锁被持有时间长的话,Ja原创 2020-07-22 12:11:52 · 459 阅读 · 0 评论 -
使用RecursiveTask执行多个任务
代码demo:import java.util.concurrent.*;public class ForkJoinDemo { static class RecursiveTaskA extends RecursiveTask<String> { @Override protected String compute() { try { System.out.println(Thread.cur原创 2020-07-21 22:03:47 · 598 阅读 · 0 评论 -
Java虚拟机对内部锁的优化
从Java6/Java7开始,Java虚拟机对内部锁的实现做了一些优化,包括锁消除,锁粗化,偏向锁及适应性锁。不过这些优化仅在Java虚拟机server模式下起作用,所以在做运行Java程序时,我们需要在命令行中指定Java虚拟机参数”-server”来开启这些优化。可以通过命令行 java-version来查看本机的虚拟机模式,如下:可以发现本机Java虚拟机默认是在server模式下运行的。...原创 2020-07-21 22:02:05 · 191 阅读 · 0 评论 -
有了锁消除后,就能随意的使用锁了么?
锁消除是JIT编译器对内部锁具体实现所做的一种优化手段, JIT编译器会借助逃逸分析来判断同步块中所使用的锁对象是否只能够被一个线程访问,如果确实没有其他线程能够访问到这个锁对象,那么JIT编译器在编译这个同步块时就不会生成synchronized关键字所对应的字节码指令,不过这不意味着开发可以随意的在不需要加锁的情况下加锁,因为锁消除是由JIT编译器做的优化,而不是javac,而一段代码只有被执行的频率足够大时,才可能被JIT编译器优化,所以可以这样说,只要同步块执行的频率没达到JIT编译器的要求,那么该原创 2020-07-21 22:01:10 · 138 阅读 · 0 评论 -
volatile关键字能修饰在哪些地方?
volatile关键字可以修饰在类变量或者实例变量上,不能修饰在方法参数,局部变量,实例常量以及类常量上。原创 2020-07-20 12:15:30 · 2101 阅读 · 0 评论 -
CPU缓存不一致性问题的两种处理方式
由于CPU的读写速度远远大于内存的读写速度,所以为了解决CPU访问主内存效率低下的问题,CPU引入了缓存。这时因为主内存和缓存都会存有数据,那么势必要保证缓存中的数据和主内存数据的一致。特别是多线程情况下,如果两个线程同时从CPU缓存中读取的值i为1,二者同时对i+1,然后写回主内存,那么i的值回变为2,但实际上i进行了2次+1的操作,实际值应该是3。这就是CPU缓存不一致导致的问题。解决方法:总线加锁,由于CPU和其他组件都是通过总线(数据总线,控制总线,地址总线)来通信,不过如果采用总线加锁的.原创 2020-07-20 12:15:06 · 2040 阅读 · 0 评论 -
JMM中的工作内存指的是什么?
工作内存包括了缓存,寄存器,编译器优化及硬件等,工作内存是一个笼统的抽象的概念,实际上并不存在。原创 2020-07-20 12:13:37 · 586 阅读 · 0 评论 -
什么时候工作内存中变量最新的值会被刷回主内存?
什么时候工作内存中变量最新的值会被刷回主内存,时间是不确定的,所以很可能会导致,明明一个线程已经执行了变量的修改操作,另一个线程取得的变量值却还是旧的,这时候可以使用volatile关键字,它的效果之一就是,工作内存中的共享变量一旦修改结束,就会立即将该变量刷新回主内存。...原创 2020-07-20 12:12:19 · 1652 阅读 · 0 评论