线程并发
文章平均质量分 79
叶光尘
这个作者很懒,什么都没留下…
展开
-
获取子线程执行结果
Callable类似于Runnable,被其他线程执行的任务实现call方法有返回值FutureCallable和Future的关系我们可以用Future.get来获取Callable接口返回的执行结果还可以通过Future.isDone()来判断任务是否已经执行完了,以及取消这个任务,限时获取任务的结果等。在call()未执行完毕之前,调用get()的线程(假定此时是主线程)会被阻塞,直到call()方法返回了结果后,此时future.get()才会得到该结果,然后主线程才会切换到run原创 2020-09-08 20:37:10 · 590 阅读 · 0 评论 -
AQS
AQSAQS的作用AQS是一个用于构建锁、同步器、协作工具类的工具类(框架)。有了AQS以后,更多的协作工具类都可以很方便得被写出来一句话总结:有了AQS ,构建线程协作类就容易多了。AQS最核心的就是三大部分:state控制线程抢锁和配合的FIFO队列期望协作工具类去实现的获取释放等重要方法state:这里的state的具体含义,会根据具体实现类的不同而不同,比如在Semaphore里,它表示"剩余的许可证的数量" ,而在CountDownLatch里,它表示"还需原创 2020-09-08 20:35:49 · 161 阅读 · 0 评论 -
控制并发流程
控制并发流程通过控制并发的工具类,帮助程序员更容易让程序之间相互合作,来满足业务逻辑CountDownLatch倒数门闩倒数结束前,一直处于等待状态,知道倒计时结束了,此线程才继续工作。主要方法:CountDownLatch(int count):构造函数,参数count为需要倒数的数值。await():调用await()方法的线程会被挂起,它会等待count的值为0才会继续执行。countDown():将count值减1,直到为0时,等待的线程会被唤起。扩展用法:多个线程等待多个线原创 2020-09-08 20:33:06 · 186 阅读 · 0 评论 -
并发容器
并发容器ConcurrentHashMap:数据安全的HasnMap。CopyOnWriteArrayList:数据安全的List。BlockingQueue:这是一个借口,表示一个阻塞队列,非常适合做数据交互通道。ConcurrentLinkedQueue:高效的非阻塞并发队列,使用链表实现。可以看做一个线程安全的LinkedList。ConcurrentSkipListMap:是一个Map,使用跳表的数据结构进行快速查询。为什么HashMap是线程不安全的?同时put碰撞导致数据丢失原创 2020-09-08 20:23:36 · 109 阅读 · 0 评论 -
不变性Final
不变性(Immutable):如果对象在被创建后,状态就不能被修改,那么它就是不可变的例子:person对象,它的所有属性 age和name都是不可变的,它就是不可变的。具有不变性的对象一定是线程安全的,我们无需对其采用额外安全措施。final:类防止被继承、方法防止被重写、变量防止被修改。天生是线程安全带额,从而不需要额外的同步开销。final三种用法:final修饰变量final修饰方法final修饰类final修饰变量被final修饰的变量,意味着值不能被.原创 2020-08-31 21:07:29 · 119 阅读 · 0 评论 -
CAS
CAS:并发我认为V的值应该是A,如果是的话我就把它修改成B,如果不是A(就说明被别人修改过了),那我就不修改了,避免多人同时修改导致出错。CAS有三个操作数:内部值V、预期值A、要修改的值B,当且仅当预期值A和内存值V相同时,才将内存值修改为B,否则什么都不做。随后返回现在的V值。在java里如何利用CAS实现原子操作:AtomicInteger加载Unsafe工具,来直接操作内存数据。用Unsafe来实现底层操作。用volatile修饰value字段,保证可见性。getAndAdd原创 2020-08-31 20:36:27 · 117 阅读 · 0 评论 -
原子类
原子类原子类不可分割一个操作是不可中断的,即使是多线程情况下也可以保证java.util.concurrent.atomic原子类的作用和锁类似,是为了保证并发情况下线程安全、不过原子类比锁有一定得优势:粒度更细:原子变量可以把竞争范围缩小到变量级别,这是我们可以获得的最细粒度的情况了,通常锁的粒度都要大于原子变量的粒度。效率更高:通常,使用原子类的效率会比使用锁的效率更高,除了高度竞争的情况。AtomicInteger常用方法:getAndDecrement() 获原创 2020-08-31 20:11:40 · 286 阅读 · 0 评论 -
锁
Lock:锁是一种工具,用于控制对共享资源的访问。Lock和Synchronized,这两个是最常见的锁,他们都可以达到线程安全的目的,但是在使用上合功能上又有很大的不同。Lock并不是用来代替synchronized的,而是当使用synchronized不合适或不足以满足要求时,来提供高级功能的。Lock接口最常见的实现类是ReentrantLock。通常情况下,Lock只允许一个线程来访问共享资源,不过有的时候,一些特殊的实现也可以允许并发访问,比如ReadWriteLock里面的Read.原创 2020-08-31 19:13:11 · 138 阅读 · 0 评论 -
ThreadLocal
什么时候需要使用ThreadLocal每个线程需要一个独享的对象,选择initialValue保存对象(通常是工具类,典型需要的类有SimpleDateFormat和Random)每个线程需要保存全局变量,可以让不同方法直接调用,避免参数传递的麻烦,用set方法保存对象第一种/** * 利用threadLocal给每个线程分配自己的dataformat对象,保证了线程安全,高效利用线程。 */public class ThreadLocalNormalUsege05 { p.原创 2020-08-31 18:58:13 · 136 阅读 · 0 评论 -
线程池
线程池线程池参数介绍corePoolSize:核心线程数:线程池在完成初始化时,在默认情况下,线程池并没有任何线程,线程池会在等待任务到来时再创建线程去执行。maxPoolSize:线程池有可能会在核心线程数的基础上,额外增加一些线程,但这些新增加的线程有一个上限,就是maxPoolSize。keepAliveTime:如果线程池当前线程多余corePoolSize,那么如果多余的线程空闲时间超过keepAliveTime,它们就会被终止。ThreadFactory:新的线程是由Thread原创 2020-08-31 18:51:01 · 174 阅读 · 0 评论 -
活跃性问题(活锁、饥饿)
死锁是最常见的活跃性问题,不过除了死锁之外,还有一些类似的问题,会导致程序无法顺利执行,统称为活跃性问题。活锁什么是活锁虽然线程没有阻塞,也始终在运行,但是程序却得不到进展,因为始终在做重复的事代码演示/** * 演示活锁问题 */public class LiveLock { //勺子类 static class Spoon { //勺子所属这 private Diner owner; public Spoon(Di.原创 2020-08-21 00:36:09 · 277 阅读 · 0 评论 -
活跃性问题(死锁)
什么是死锁?发生在并发里。互不相让:当两个(或多个)线程(或进程)相互持有对方锁需要的锁,又不主动释放,导致所有人都无法继续前进,导致程序陷入无尽的阻塞,这就是死锁。如果多个线程之间的依赖关系是环形,存在环路的锁的依赖关系,那么也可能发生死锁。死锁的影响几率不高单危害大必定发生死锁最简单的例子/** * 必定发生死锁 */public class MustDeadLock implements Runnable{ int flag = 1; .原创 2020-08-21 00:32:24 · 198 阅读 · 0 评论 -
单例模式的8种写法
单例模式的8种写法第四个和第六个更好。第一种:饿汉式(静态常量)(可用)/** * 饿汉式(静态常量)(可用) */public class Singleton1 { private final static Singleton1 INSTANCE = new Singleton1(); private Singleton1() { } public static Singleton1 getInstance(){ return INSTANCE;原创 2020-08-20 00:49:08 · 430 阅读 · 0 评论 -
JVM内存结构、Java对象模型、Java内存模型(JMM)
JVM内存结构JVM内存结构:java代码是运行在虚拟机上,虚拟机会将内存分为不同的区域,每个区域又有不同的作用。class文件经过类加载器转换后会到达运行数据区,即Runtime Data Area。绿色的(方法区和堆)是线程共享的,黄色的(java栈,本地方法栈和程序计数器)是线程私有的。堆(heap):最大的一块,也占用内存最多。里面主要是new出来的已经其他指令创建的实例对象,并且这些实例对象不再有引用的话会被垃圾回收,包括数组,因为数组也是对象。虚拟机栈(VM stack):也就是上图原创 2020-08-20 00:33:32 · 189 阅读 · 0 评论 -
多线程带来的性能问题
多线程带来的性能问题:调度:上下文切换什么是上下文切换:当一个线程调用Thread.sleep()想进入阻塞状态,线程调度器就会阻塞这个线程,然后让另一个等待CPU资源的线程进入的Runnable状态,这个动作就是一个上下文切换。开销很大,有时比线程执行时间都长,通常一次上下文切换会消耗5000-10000个CPU时钟周期,大约是几微秒,对于CPU而言,是一个很大的开销了。什么是上下文:一次上下文切换,主要包含以下活动,首先要挂起一个线程,然后把这个线程的状态存在内存的某处,这个状态就是上下文。原创 2020-08-17 02:45:12 · 481 阅读 · 0 评论 -
线程安全第三大类问题——对象发布和初始化的安全问题
线程安全第三大类问题——对象发布和初始化的安全问题什么是发布:将对象可以超过这个类范围之外可以使用;比如对象声明为public,或者方法的return是一个对象,或者将类作为参数传到其他类的方法中,这些都能称之为发布。什么是逸出:发布到了不该发布的地方就叫逸出。1.方法返回一个private对象(private本意是不让外部访问)2.还未完成初始化(构造函数没完全执行完毕)就把对象提供给外界。比如:在构造函数中未初始化完毕就this赋值隐式逸出——注册监听事件构造函数中运行线程对于逸出的原创 2020-08-17 01:36:43 · 160 阅读 · 0 评论 -
线程安全第二大类问题——死锁
线程安全第二大类问题——死锁逻辑代码:package controller;/** * 第二类线程安全问题:死锁 */public class MultiThreadError implements Runnable{ int flag = 1; static Object o1 = new Object(); static Object o2 = new Object(); public static void main(String[] args) {原创 2020-08-16 23:41:22 · 115 阅读 · 0 评论 -
线程安全第一大类问题——运行结果出错
线程安全第一大类问题之运行结果出错a++多线程下出现消失的请求现象逻辑代码(注释很详细,直接看代码):package controller;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;import java.util.concurrent.atomic.AtomicInteger;/** * 第一种:运行结果出错 * 演示计数不准确,减少,找出具原创 2020-08-16 21:52:18 · 496 阅读 · 0 评论 -
什么是线程安全
什么是线程安全?当多个线程访问一个对象,如果不用考虑这些线程在运行环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象就是线程安全的。线程不安全:比如使用Set集合考虑交替调度,如get的时候不能同时set、或者进行额外同步,比如使用synchronized修饰;我们考虑了交替调度和做了额外同步,所以不能说它是线程安全的。上篇:处理多线程子线程的异常UncaughtExceptionHandler...原创 2020-08-16 21:45:30 · 188 阅读 · 0 评论 -
处理线程未捕获的异常UncaughtExceptionHandler
为什么需要UncaughtExceptionHandler?1.主线程可以轻松发现异常,子线程却不行(比如子线程抛出了RuntimeException异常,而主线程start子线程后后续还有很多逻辑,子线程的异常可能夹杂在日志里无法轻松发现)。2.子线程异常无法用传统方法捕获(比如在主方法里try/catch不能捕获到子线程里面的异常,他只能捕获主线程的异常)。处理多线程子线程的异常有两种方式:第一种是手动在每个run方法里进行try/catch,不推荐这种方式,写起来繁琐。第二种是利用Uncau原创 2020-08-16 18:03:59 · 1132 阅读 · 0 评论 -
线程4个属性
线程4个属性线程ID:每个线程都有自己的ID,用来标识不同的线程。JVM就用ID辨识线程,这个属性虽然在每一次JVM启动是唯一的,下一次创建线程,它又会从1开始往上编号,所以同一个ID会被先后不同的线程使用,唯一性不能保证;ID不允许被修改。ID是从1开始,并自增的,JVM运行起来后,我们自己创建的线程ID早已经不是1也不等于2,因为JVM 会自动创造一些线程,比如去做初始化、gc等。Thread.currentThread().getId();线程Name:作用是让程序员在开发、调试或运行过程中,更容原创 2020-08-16 09:51:47 · 2976 阅读 · 0 评论 -
Thread的常用方法sleep和join详解
sleep方法可以让线程进入到Waiting状态,并且不占用CPU资源,但是不释放锁,知道规定时间后再执行,休眠期间如果没中断,会抛出异常并清除中断状态。sleep()和wait()区别1.sleep对比wait最大的区别就是sleep不释放锁,包括synchronized和lok。而wait会释放锁。2.sleep()在Thread类里,wait()在Object类里,wait(),notifyAll(),notify()在Object对象里,因为这三个是锁级别的操作,而锁是属于某个对象的,每个对象原创 2020-08-16 02:03:14 · 2134 阅读 · 0 评论 -
两个线程交替打印0~100的即偶数
用wait和notify/** * 两个线程交替打印0~100的寄偶数,用wait和notify */public class WaitNotifyPrintOddEvenWait { private static int count = 0; private static final Object lock = new Object(); public static void main(String[] args) { new Thread(new Tur原创 2020-08-15 19:28:56 · 241 阅读 · 0 评论 -
手写一个生产者消费者模式
用wait/notify实现开发者消费者模式,之前博客使用阻塞队列BlockingQueue也实现过开发者消费者模式。以下的代码和main方法都写在一个文件里就行。第一步:我们首先需要一个容器storage,我们将它定义为LinkedList是为了使用它的poll方法,一步实现拿出并删除,当然也可以使用ArrayList,然后使用get(0) + remove()拿出删除产品。这个容器类一个干了三件事,1.定义容器并初始化。2.实现往容器放产品,即创建put方法,供生产者调用。3.实现从容器里取出原创 2020-08-15 19:20:30 · 633 阅读 · 0 评论 -
线程的6个状态
线程的6个状态New:线程刚创建的状态;Runnable:调用start()后的状态,可以对应操作系统的ready running状态;Blocked:进入到synchronized修饰的代码块或方法并已经被其他线程获得monitor锁;注意:一定是遇到synchronized才会出现,其他的锁虽然也会是线程陷入等待,但是不会是线程进入到Blocked状态;当获得了monitor锁就会回到Runnable状态;Waiting:使线程进入到等待的方法Object.wait()Threa原创 2020-08-12 22:06:34 · 355 阅读 · 0 评论 -
合理的停止一个Java线程
怎样合理的停止一个Java线程在Java中,最好的停止线程的方式是使用中断 Interrupt,但是这仅仅是会通知到被终止的线程你该停止运行了”,被终止的线程自身拥有决定权(决定是否、以及何时停止),这依赖于请求停止方和被停止方都遵守一种约定好的编码规范。任务和线程的启动很容易。在大多数时候,我们都会让它们运行直到结束,或者让它们自行停止。然而,有时候我们希望提前结束任务或线程,或许是因为用户取消了操作,或者服务需要被快速关闭,或者是运行超时或出错了。要使任务和线程能安全、快速、可靠地停止下来,并不是原创 2020-08-10 23:13:48 · 170 阅读 · 0 评论 -
创建线程的两个方法(Oracle官网说两种)
一.有多少种实现多线程的方法?1.不同的角度有不同的答案2.典型的答案有两种,分别是实现Runnable接口和继承Thread类3.但是看原理,其实Thread类实现了Runnable接口,并且看Thread类的run方法,会发现其两者本质是一样的,run方法发代码如下:@OverridePublic void run(){ if(target != null){ target.run(); }}方法1和方法2,也就是说“实现Runnable类”和“继承Thread类然后重写run(原创 2020-08-09 18:07:19 · 1652 阅读 · 0 评论