![](https://img-blog.csdnimg.cn/20201014180756928.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
java并发编程
黑皮爱学习
爱学习,爱分享!
展开
-
7.6 并发下性能的开销,和较少锁竞争提高效率的方法
引入多线程之后,其实会产生额外的开销思维导图链接:https://www.edrawsoft.cn/viewer/public/s/08a7d277155352原创 2020-07-11 17:11:02 · 106 阅读 · 0 评论 -
7.5 活锁和线程饥饿
活锁:两个或以上线程在尝试拿锁的时候,发生了线程之间的相互谦让,不断发生同一个线程总是拿到通一把锁,在尝试拿另一把锁是因为拿不到,而将本来已经持有的锁释放的过程解决方法:让每个线程随即休眠一段时间,错开拿锁的时间线程饥饿:低优先级的线程,总是拿不到执行时间...原创 2020-07-11 10:33:46 · 117 阅读 · 0 评论 -
7.4 死锁的定位方法
7.4 实现动态顺序死锁原创 2020-07-11 10:25:20 · 324 阅读 · 0 评论 -
7.3 实现顺序死锁代码
简单顺序死锁的条件1、两个线程1,22、两个资源a,b3、两个线程先获取不同的资源(使用Thread.sleep)demopublic class TestDeadLock { static class CustomerA extends Thread{ Object a; Object b; public CustomerA(Object a, Object b) { this.a = a; ...原创 2020-07-10 23:44:09 · 116 阅读 · 0 评论 -
7.2 产生死锁的四个必要条件、解决死锁的常用方式(有序资源法和银行家算法)
1 死锁的定义两个或者两个以上线程在执行过程中,因为竞争资源或者彼此通信而造成的一种阻塞现象,如果没有外力作用,他们都将无法进行下去。此时称系统处于死锁状态或者系统产生了死锁2 死锁产生的四个必要条件互斥条件 两个条件a和吧,两个线程都要得到这两个资源才能运行, 线程1获得了a等待获取b,线程2获取了b等待获取a,两个线程相互竞争、等待,产生死锁 请求和保持条件 1、线程已经保持至少一个资源,并保持这个资源不释放:保持不释放 2、线程要获取原创 2020-07-10 23:31:25 · 647 阅读 · 0 评论 -
7.1 什么是线程安全的类,实现线程安全对象的常用方法总结
在《Java并发编程实战》中,定义如下:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在调用代码中不需要任何额外的同步或者协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。实现线程安全的类常用方式线程封闭 把对象封装到线程中,只有这个线程能够看到此对象 无状态的类 没有任何成员变量的类 让类不可变 1、加final关键字 2、不提供修改成员变量,也不提供获取成员变量方法 使用volatile原创 2020-07-10 23:10:13 · 589 阅读 · 0 评论 -
6.6 CompletionService的理解、使用示例
6.6 CompletionService的理解、使用示例原创 2020-07-09 23:16:42 · 204 阅读 · 0 评论 -
6.5 java预定义线程池Executors生成Fixed、Single、Cached 、ScheduledThread对比和适用场景分析
预定义线程池 特点 适用场景 FixedThreadPool 1、固定线程数; 2、多余的空闲线程立马终止 负载较重场景,即资源较少的场景 SingleThreadExecutor 1、只要一个线程执行 2、保证任务执行顺序,上一个 任务执行完毕,下一个才会执行 保证任务的执行顺序 CachedThreadPool 1、使用无界队列 2、没有空闲线原创 2020-07-08 22:37:46 · 464 阅读 · 0 评论 -
6.5.4 java预定义线程池ScheduledThreadPoolExecutor 理解、使用示例
目录两个构造方法有两种类型构造理解适用场景周期线程池执行的常用方法使用demo1:newSingleThreadScheduledExecutor的顺序执行schedule:延时3秒执行scheduleAtFixedRate:固定时间间隔执行任务scheduleWithFixedDelay:然后执行完任务后,延迟3秒再周期执行当前任务如果不了解线程池的各个参数的含义,可以查看此文章线程池的优点、以及各个参数的意义、使用示例两个构造方法一个多了一个线程工厂的..原创 2020-07-08 22:21:04 · 507 阅读 · 0 评论 -
6.5.3 java预定义线程池CachedThreadPool 理解、使用示例
如果不了解线程池的各个参数的含义,可以查看此文章线程池的优点、以及各个参数的意义、使用示例两个构造方法一个多了一个线程工厂的参数,能够对参数名等进行设置 public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executorService1 = Executors.newCachedThreadPool (); .原创 2020-07-08 21:43:04 · 665 阅读 · 0 评论 -
6.5.2 java预定义线程池SingleThreadExecutor 理解、使用示例
如果不了解线程池的各个参数的含义,可以查看此文章线程池的优点、以及各个参数的意义、使用示例四个构造方法一个多了一个线程工厂的参数,能够对参数名等进行设置;返回带延迟、循环执行的单例线程池public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executorService1 = Executors.newSingleTh.原创 2020-07-08 21:31:21 · 867 阅读 · 0 评论 -
6.5.1 java预定义线程池FixedThreadPool理解、使用示例
如果不了解线程池的各个参数的含义,可以查看此文章线程池的优点、以及各个参数的意义、使用示例两个构造方法一个多了一个线程工厂的参数,能够对参数名等进行设置 public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool(3); .原创 2020-07-08 20:43:56 · 653 阅读 · 0 评论 -
6.4 合理地分配线程池ThreadPoolExecutor的大小、以及阻塞队列的选择
要合理分配线程池,必须分析所执行任务的特性任务特性对比任务的特性 CUP密集型任务 IO密集型任务 混合型任务 要想合理地配置线程池,就必须首先分析任务特性要想合理地配置线程池,就必须首先分析任务特性,可以从以下几个角度来分析。•任务的性质:CPU密集型任务、IO密集型任务和混合型任务。•任务的优先级:高、中和低。•任务的执行时间:长、中和短。•...原创 2020-07-08 20:13:19 · 3885 阅读 · 0 评论 -
6.4 ThreadPoolExecutor线程池的关闭方法shutdown和shutdownNow区别、示例
shutdown():把线程池的状态设置成SHUTDOWN状态,然后中断所有没有正执行任务的线程shutdownNow():首先把线程池的状态设置成STOP,然后尝试停止所有正在执行任务或者暂停任务的线程,并返回等待执行任务的列表常用通常我们调用shutdown()方法关闭线程池,如果不需要任务执行完成,可以调用shutdownNow()原理遍历线程池中的工作线程,然后组个调用线程的interrupt方法来中断线程,所以无法响应中断任务的可能永远无法停止其他方法isShu原创 2020-07-07 23:31:50 · 12958 阅读 · 0 评论 -
6.3 线程池的execute()和submit()的区别和使用示例
execute()方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功。submit()方法用于提交需要返回值的任务。线程池会返回一个future类型的对象,通过这个future对象可以判断任务是否执行成功,并且可以通过future的get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成,而使用get(long timeout,TimeUnit unit)方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。package cn.enjoyedu.ch1原创 2020-07-07 20:35:23 · 1227 阅读 · 0 评论 -
6.2 线程池的扩展beforeExecute和afterExecute参数说明和使用示例
线程池ThreadPoolExecutor为了提供扩展,提供了protected的两个方法beforeExecute和 afterExecute,每个任务执行前后都会调用这两个方法,相当于对线程任务的执行做了一个切面线程池中定义的两个空方法public class ThreadPoolExecutor extends AbstractExecutorService { /** * @param t 执行任务的线程 * @param r 将要被执行的任务原创 2020-07-06 22:46:40 · 4535 阅读 · 0 评论 -
6.1 线程池的优点、以及各个参数的意义、使用示例
6、线程池为什么要用线程池? Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行任务的程序都可以使用线程池。在开发过程中,合理地使用线程池能够带来3个好处。第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。 如果:T1 + T3 远大于 T2,则可以采用线程池,以提..原创 2020-07-06 10:31:04 · 716 阅读 · 0 评论 -
阻塞队列BlockingQueue
特点:支持阻塞插入:当队列满的时候,会阻塞元素的插入,知道队列不满支持阻塞移除:当队列为空时,获取元素的线程会等待队列变为非空使用场景:阻塞队列常用与生产者和消费者的场景,生产者往队列中添加元素,消费者从队列中获取元素常用方法和处理方式方法、处理方式 队列满抛出异常 返回特殊值 阻塞 超时退出 插入 add(e) offer(e) put(e) offer(e,time,unit) 移除 remove() po...原创 2020-07-05 22:38:57 · 285 阅读 · 0 评论 -
4.5.8 SynchronousQueue简单使用示例
是一个不存储元素的阻塞队列。每一个put操作必须等待一个take操作,否则不能继续添加元素。本身不存储元素,只是负责传递(但是使用起来就像是只能够存储一个元素的队列)demopublic class Test extends Thread { public static void main(String[] args) throws InterruptedException { SynchronousQueue queue = new SynchronousQueue原创 2020-07-05 22:38:35 · 178 阅读 · 0 评论 -
4.5.7 DelayQueue实现缓存设计
实体:public class MyDelayed implements Delayed { private String key; private long currentTime; private long expireTime; public MyDelayed(String key, long expireTime) { this.key=key; this.expireTime=expireTime; this原创 2020-07-05 22:35:09 · 213 阅读 · 0 评论 -
4.5.6 DelayQueue简单使用demo
支持延时获取元素的无界阻塞队列,队列元素必须实现Delayed接口,在创建元素的时候可以指定多久才能从队列中获取当前元素。时间到了才能从队列中获取到元素简单使用实体implements Delayedpublic class MyDelayed implements Delayed { private String key; private long currentTime; private long expireTime; public MyDelayed(原创 2020-07-05 22:33:15 · 301 阅读 · 0 评论 -
4.5.5PriorityBlockingQueue简介和基本使用demo
支持优先级的无界阻塞队列:默认情况下元素采取自然顺序升序排列,可以以自定义compareTo()方法来指定元素的排序规则。demo:通过年龄比较大小,实现Comparable实体public class Person implements Comparable { private String name; private Integer age; public Person(String name, Integer age) { this.name =原创 2020-07-05 22:31:05 · 334 阅读 · 0 评论 -
4.5.3写时复制容器CopyOnWriteArrayList和CopyOnWriteArraySet理解、优点和使用场景
理解CopyOnWrite就是写时复制容器。在写入数据的时候,会从源容器复制出一个新容器,然后在新容器中添加元素,添加完成之后,再让源容器指针指向新容器。写时复制容器的好处可以对CopyOnWrite并发读取,而不需要加锁,因为当前容器不会添加任何元素。这是一种读写分离的思想,读和写分别使用不同的容器写时复制容器的缺点1、每次修改都会新建一个数组,如果源数组很大,修改操作比较频繁,性能就会很低,内存会有大开销2、数据一致性问题:因为修改并不会马上就能够被读到,即只能保证最终一致性原创 2020-07-04 17:51:05 · 518 阅读 · 0 评论 -
4.5.4 无界不阻塞队列ConcurrentLinkedQueue 原理、常用方法、使用示例
理解:可以看成是LinkedList的并发版本底层原理:单项链表特点先进先出、无界(能存储数量没有限制)构造方法public ConcurrentLinkedQueue():首尾都是空的链表public ConcurrentLinkedQueue(Collection<? extends E> c):把集合的元素放入链表常用方法:concurrentLinkedQueue.add("c"); 新增元素boolean addAll(Colle...原创 2020-07-04 15:28:50 · 519 阅读 · 0 评论 -
LinkedList的原理和方法介绍、使用
LinkedList底层是双向链表 private static class Node<E> { E item;//当前元素 Node<E> next;下一个元素 Node<E> prev;上一个元素 Node(Node<E> prev, E element, Node<E> next) { this.item = element;原创 2020-06-27 17:40:28 · 619 阅读 · 0 评论 -
4.7 并发下常见的Map面试题汇总
1、HashMap和HashTable的区别1、HashMap线程不安全,HashTable线程安全2、因为线程安全,HashTable效率比HashMap低3、HashTable的key和value都不能为空,HashMap只能有一个key为null,多个value值为null4、HashMap默认初始数组大小是16,HashTable默认是11,HashMap扩容2倍,HashTable扩大两倍+15、HashMap需要重新计算hash值,而HashTable直接使用兑现过的hash原创 2020-06-25 22:28:17 · 197 阅读 · 0 评论 -
4.6 HashTable简单介绍
HashTable容器使用synchronized来保证线程的安全,但是在线程精致激烈的情况下HashTable的效率非常低下。因为当一个贤臣个访问HashTable的同步方法,其他线程也访问HashTable的同步方法是,会阻塞或轮询状态,如果线程1使用put进行元素天机啊,线程2不但不能put方法添加元素,也不能使用get方法获取元素,所以竞争越激烈效率越低。HashTable的key和value都不能是null...原创 2020-06-25 22:07:41 · 160 阅读 · 0 评论 -
4.5.2 ConcurrentHashMap的实现分析包含1.7和1.8对比分析
opp原创 2020-06-25 22:01:10 · 327 阅读 · 0 评论 -
4.5.1HashMap死循环分析
注:源图和总结来自享学课堂,自己消化之后略有补充修改备注:基于1.7jdk进行分析备注2:强烈建议自己跟着步骤一个图一个图手动画,理解深刻一点也快一点简介在多线程之下,在put操作的时候,会导致HashMap的Entry链表死循环,导致CPU利用率接近100%单线程下HashMap的扩容原理扩容只要有三个方法:AddEntryresizetransfer扩容总结1、扩容2倍2、新建数组,容量是以前的2倍3、轮询oldtable上的值,计算在原创 2020-06-24 23:41:17 · 225 阅读 · 0 评论 -
4.4 AQS即AbstractQueuedSynchronizer 基本方法和通过AQS的实现自定义锁并使用测试
AQS使用方式和其中的设计模式 AQS使用了模板模式,定义了线程操作需要的基本末班,继承子类只需要按照这些模板去操作AQS常用的模板方法名方法名称 描述 void acquire(int arg) 独占式获取同步状态,如果当前线程获取同步状态成功,则返回; 否则就会进入同步队列等待,该方法将会调用重写的tryAcquire(int arg)方法 void acquireInterruptibly(int arg) 与acquire(int原创 2020-06-20 18:37:22 · 124 阅读 · 0 评论 -
4.3 使用lock的condition实现等待/通知机制
Condition接口任意一个Java对象,都拥有一组监视器方法(定义在java.lang.Object上),主要包括wait()、wait(long timeout)、notify()以及notifyAll()方法,这些方法与synchronized同步关键字配合,可以实现等待/通知模式。Condition接口也提供了类似Object的监视器方法,与Lock配合可以实现等待/通知模式。Condition常用方法Condition使用范式示例:...原创 2020-06-19 14:59:11 · 294 阅读 · 0 评论 -
4.2 ReentrantReadWriteLock读写锁的理解和简单示例
ReentrantReadWriteLock读写锁的特点:1、允许多个读线程同时访问,读访问时,写锁不能访问2、当有写线程访问时,其他的读和写线程都不能够访问3、编程方式相对于使用等待通知机制:写的时候,其他的读写都阻塞,保证每次读取到的都是最新的数据4、在读多于写的情况下,读写锁能够提供比排它锁更好的并发性和吞吐量ReentrantReadWriteLock其实实现的是ReadWriteLock接口使用的标准方式readLock.lock();try { //DoSome原创 2020-06-18 20:05:09 · 171 阅读 · 0 评论 -
4.1 显示锁ReentrantLock的理解,使用示例
ReentrantLock有了synchronized为什么还要Lock Synchronized lock 类型 关键字:修饰方法或者代码块 接口:常用的五个方法 lock常用的方法lock使用的标准代码lock.lock();try{ count++; }finally{ lock.unLock();}ReentrantLock使用示例:两个线程对count自增1000,另一个线程对...原创 2020-06-17 23:05:22 · 200 阅读 · 0 评论 -
3.3 引用类型的原子操作类AtomicReference使用示例
AtomicStampedReference利用版本戳的形式记录了每次改变以后的版本号,这样的话就不会存在ABA问题了。这就是AtomicStampedReference的解决方案。AtomicMarkableReference跟AtomicStampedReference差不多, AtomicStampedReference是使用pair的int stamp作为计数器使用,AtomicMarkableReference的pair使用的是boolean mark。 还是那个水的例子,AtomicStam原创 2020-06-17 15:26:37 · 342 阅读 · 0 评论 -
3.5 引用类型的原子操作类AtomicMarkableReference使用示例
AtomicMarkableReference:基本和AtomicStampedReference差不多,AtomicStampedReference主要关注版本号,即reference的值被修改了多少次;AtomicMarkableReference是使用boolean mark来标记reference是否被修改过示例如下public class MyAtomicMarkableReference { static AtomicMarkableReference<String&原创 2020-06-17 15:26:24 · 1200 阅读 · 1 评论 -
3.4 引用类型的原子操作类AtomicStampedReference使用示例
AtomicStampedReference:解决CAS的ABA问题AtomicInteger无法知道中间值有没有被修改过,AtomicStampedReference通过整形final int stamp;来标记Integer值修改过多少次代码示例:public class MyAtomicStampedReference { //版本是,以后每修改一次都会增加1,如果修改时和自己预料的版本不一致就会修改失败 static AtomicStampedReference<原创 2020-06-17 15:24:23 · 448 阅读 · 1 评论 -
3.2 AtomicIntegerArray 的简单使用
注:原始代码来自享学课堂,自己理解消化略有修改AtomicIntegerArray主要是提供原子的方式更新数组里的整型其常用方法如下•int addAndGet(int i,int delta):以原子方式将输入值与数组中索引i的元素相加。•boolean compareAndSet(int i,int expect,int update):如果当前值等于预期值,则以原子方式将数组位置i的元素设置成update值。需要注意的是,数组value通过构造方法传递进去,然后AtomicIn..原创 2020-06-16 22:49:09 · 499 阅读 · 0 评论 -
3.1 原子操作类AtomicInteger 的理解和使用
AtomicInteger 常用的几个方法int addAndGet(int delta):以原子方式将实例中的值与输入的值delta相加,并返回结果boolean compareAndSet(int expect, int update):如果输入的值expect等于预期值,就以原子方式把值设置为updateint getAndIncrement():以原子方式获取值之后,增加1int getAndSet(int newValue):以原子方式获取当前值,然后设置一个值多线程对普通变量原创 2020-06-16 22:40:41 · 453 阅读 · 0 评论 -
2.4 fork/join的快速理解和基本使用示例、读取文件夹下所有文件、计算大数组的和
1、读取文件夹下文件2、分散计算总数原创 2020-06-16 09:13:17 · 439 阅读 · 0 评论 -
2.3 Exchanger的理解和使用
package cn.enjoyedu.ch2.tools;import java.util.HashSet;import java.util.Set;import java.util.concurrent.Exchanger;/** *类说明:演示Exchange用法 */public class UseExchange { private static final Exchanger<Set<String>> exchange = new Exchan.原创 2020-06-15 20:06:06 · 131 阅读 · 0 评论