关于juc:Future和CompletableFuture

1.Future不能手动实现2.Future的后果,只能在阻塞的状况下进一步操作。 get()是阻塞的告诉你后果,无奈给Future手动植入一个回调函数,当Future后果可用时,用该函数调用Future的后果。3.多个Future不能串联一起组成链式调用。4.不能组合多个后果。5.没有异样解决的Future API. CompletableFuture恰好有。1.get() complete()2.runAsync()--异步,不返回 Runnable3.supplyAsync()--异步,有返回 Supplier

November 3, 2022 · 1 min · jiezi

关于juc:jucAQS源码分析1

1. AQS类了解AQS如果作为一个幼儿园老师来看,她的小名叫"锁"老师,手里拿一个"state"的玩具按钮,负责有保护孩子们玩玩具"先来后到"的秩序。如果把其余小孩叫"线程"小朋友,当他们一起玩儿滑滑梯时,每次只能上一个。此时就须要"锁"老师来守在滑滑梯口儿上:小"线程"们奔过去,谁先把"锁"老师手里的按钮state按亮了,谁就先上;按不亮的,就让"锁"老师来给你前胸后背都给你贴一个挂钩,挂着后面比你先上的小朋友和你前面紧跟着的小朋友。另外如果有某些"线程"小朋友要喝水,"锁"老师也给这些小朋友每个人头上戴一个帽子,帽子上写着下一个喝水的"线程"小朋友的名字。这样喝水也有程序了。下面的玩儿滑滑梯的程序,前后的钩子,就是AQS里外部类Node里的prev/next援用,保护"阻塞队列"的FIFO程序;它是双向的链表。下面等喝水的小朋友帽子上的名字,就是Node里的nextWaiter援用,保护"条件队列"的程序,它是单向的链表。AQS类图: 2. AQS两个队列:阻塞队列和条件队列2.1 阻塞队列2.1.1 双向链表实现的FIFO队列一个CLH队列,他是FIFO的,实现形式为双向链表的构造,具体构造定义见AQS的外部动态类Node,如果要偏心实现,就是先来后到的。 2.1.2 双向链表构造NodeFIFO队列内节点的数据结构:外部类:Node 2.2 条件队列2.2.1 单向链表的条件队列:见Node的nextWaiter阻塞队列是FIFO的,是双向链表,在Node链对象里是prev+next条件队列是单向,只存储下一个期待者的援用,在Node里是nextWaiter;应用形式如上所示2.2.2 条件队列的条件构造:AQS>ConditionObject条件队列的实现,也是在AQS中,体现在ReentrantLock里就是lock.newCondition()的Condition; sync自身就是AQS的子类. 看上面的源码:ReentrantLock的newCondition应用的是本人外部的Sync的newCondition(),而sync就是AQS,sync.newCondition()生成的就是ConditionObject。也就是AQS外部类的ConditionObject。 // ReentrantLock#newConditionpublic Condition newCondition() { return sync.newCondition();}// ReentrantLock.Sync#newConditionfinal ConditionObject newCondition() { return new ConditionObject();}2.3 一个实例条件队列和可重入锁示例: @Testpublic void testConditional() throws InterruptedException { // AQS锁 ReentrantLock lock = new ReentrantLock(); // AQS条件 Condition condition = lock.newCondition(); Thread t1 = new Thread(() -> { System.out.println("======================t1.print=============="); lock.lock(); try { System.out.println("t1 await start ...."); condition.await(); System.out.println("t1 await end"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }); Thread t3 = new Thread(() -> { System.out.println("======================t3.print=============="); lock.lock(); try { System.out.println("t3 await start ...."); condition.await(); System.out.println("t3 await end"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }); Thread t2 = new Thread(() -> { System.out.println("======================t2.print=============="); lock.lock(); try { System.out.println("signal start ...."); condition.signalAll(); System.out.println("signal end"); } finally { lock.unlock(); } }); t1.start(); t3.start(); Thread.sleep(400); t2.start();}输入后果如下: ...

October 10, 2022 · 1 min · jiezi

关于juc:JUC-之多线程锁的-8-个问题分析

程序代码package com.atguigu.thread;import java.util.concurrent.TimeUnit;class Phone{public synchronized void sendSMS() throws Exception{System.out.println("------sendSMS");}public synchronized void sendEmail() throws Exception{System.out.println("------sendEmail");}public void getHello(){System.out.println("------getHello");}}/**** @Description: 8锁* @author xialei*1 规范拜访,先打印短信还是邮件2 停4秒在短信办法内,先打印短信还是邮件3 新增一般的hello办法,是先打短信还是hello4 当初有两部手机,先打印短信还是邮件5 两个动态同步办法,1部手机,先打印短信还是邮件6 两个动态同步办法,2部手机,先打印短信还是邮件7 1个动态同步办法1个一般同步办法,1部手机,先打印短信还是邮件8 1个动态同步办法1个一般同步办法,2部手机,先打印短信还是邮件* ---------------------------------**/public class Lock_8{public static void main(String[] args) throws Exception{Phone phone = new Phone();Phone phone2 = new Phone();new Thread(() -> {try {phone.sendSMS();} catch (Exception e) {e.printStackTrace();}}, "AA").start();Thread.sleep(100);new Thread(() -> {try {phone.sendEmail();//phone.getHello();//phone2.sendEmail();} catch (Exception e) {e.printStackTrace();}}, "BB").start();}}锁的 8 个问题(1) 规范拜访,先打印短信还是邮件 (2) 停 4 秒在短信办法内,先打印短信还是邮件 ...

April 1, 2022 · 1 min · jiezi

关于juc:JUC包之Future模式

Future模式 Future模式是多线程开发中的一种常见的设计模式,核心思想异步调用,让串行化的问题变得并行处理节省时间。 当程序执行一个工作时,这个工作可能执行的很慢,它不可能立刻返回后果,但能够返回一个契约,因而咱们能够在该工作执行的时候,再去执行其它工作,最终用该契约获取后果。 举个栗子: 在网上买了一部手机,手机三天后才会到货,但会马上产生一个订单,这个订单就是上述所提到的契约,而后咱们不必始终干等手机的到来,齐全能够去忙别的事,当快递到来的时候,订单核查一下,而后就取得了最终后果。 JDK中的Future模式 Future接口相似于之前的契约,依据Future对象调用get办法最终获取到后果。 FutureTask接口实现Callable接口对象到Runnable接口对象的过渡,最终会交由Callable接口实现,Callable接口的call办法返回最终后果。 FutureTask类阐明 英文有肯定阻碍的看中文正文 /**一、订正阐明: 1、这与该类以前依赖AbstractQueuedSynchronizer的版本不同,次要是为了防止用户在勾销竞争期间意外地保留中断状态。 2、以后设计中的同步控制依赖于通过CAS更新的“state”字段来跟踪实现状况,以及一个用于保留期待线程的简略Treiber堆栈。 二、阐明: 1、与平常一样,咱们绕过了应用atomicxfielddupdater的开销,而是间接应用不平安的外部函数。 工作状态: 一、状态阐明 1、此工作的运行状态,最后为新建。 2、 运行状态仅在办法set、setException和cancel中转换为终端状态。 3、在实现过程中,状态可能会出现实现(在设置后果时)或中断(仅在中断转轮以满足勾销(true))的瞬态值。 4、从这些中间状态到最终状态的转换应用更便宜的程序/提早写入,因为值是惟一的,无奈进一步批改。 二、可能的状态转换: 1、新建->实现->失常 2、新建->实现->异样 3、新建->勾销 4、新建->中断->中断**/ /** * A cancellable asynchronous computation. This class provides a base * implementation of {@link Future}, with methods to start and cancel * a computation, query to see if the computation is complete, and * retrieve the result of the computation. The result can only be * retrieved when the computation has completed; the {@code get} * methods will block if the computation has not yet completed. Once * the computation has completed, the computation cannot be restarted * or cancelled (unless the computation is invoked using * {@link #runAndReset}). * * <p>A {@code FutureTask} can be used to wrap a {@link Callable} or * {@link Runnable} object. Because {@code FutureTask} implements * {@code Runnable}, a {@code FutureTask} can be submitted to an * {@link Executor} for execution. * * <p>In addition to serving as a standalone class, this class provides * {@code protected} functionality that may be useful when creating * customized task classes. * * @since 1.5 * @author Doug Lea * @param <V> The result type returned by this FutureTask's {@code get} methods */public class FutureTask<V> implements RunnableFuture<V> { /* * Revision notes: This differs from previous versions of this * class that relied on AbstractQueuedSynchronizer, mainly to * avoid surprising users about retaining interrupt status during * cancellation races. Sync control in the current design relies * on a "state" field updated via CAS to track completion, along * with a simple Treiber stack to hold waiting threads. * * Style note: As usual, we bypass overhead of using * AtomicXFieldUpdaters and instead directly use Unsafe intrinsics. */ /** * The run state of this task, initially NEW. The run state * transitions to a terminal state only in methods set, * setException, and cancel. During completion, state may take on * transient values of COMPLETING (while outcome is being set) or * INTERRUPTING (only while interrupting the runner to satisfy a * cancel(true)). Transitions from these intermediate to final * states use cheaper ordered/lazy writes because values are unique * and cannot be further modified. * * Possible state transitions: * NEW -> COMPLETING -> NORMAL * NEW -> COMPLETING -> EXCEPTIONAL * NEW -> CANCELLED * NEW -> INTERRUPTING -> INTERRUPTED */ private volatile int state; private static final int NEW = 0; private static final int COMPLETING = 1; private static final int NORMAL = 2; private static final int EXCEPTIONAL = 3; private static final int CANCELLED = 4; private static final int INTERRUPTING = 5; private static final int INTERRUPTED = 6; /** The underlying callable; nulled out after running */ private Callable<V> callable; /** The result to return or exception to throw from get() */ private Object outcome; // non-volatile, protected by state reads/writes /** The thread running the callable; CASed during run() */ private volatile Thread runner; /** Treiber stack of waiting threads */ private volatile WaitNode waiters; // 外部类 WaitNode // 在Treiber堆栈中记录期待线程的简略链表节点。 //无关更具体的阐明,请参见其余类,如Phaser和SynchronousQueue。 /** * Simple linked list nodes to record waiting threads in a Treiber * stack. See other classes such as Phaser and SynchronousQueue * for more detailed explanation. */ static final class WaitNode { volatile Thread thread; volatile WaitNode next; WaitNode() { thread = Thread.currentThread(); } }简略应用 ...

February 25, 2022 · 5 min · jiezi

关于juc:JUC之多线程锁的8个问题分析

程序代码package com.atguigu.thread;import java.util.concurrent.TimeUnit;class Phone{public synchronized void sendSMS() throws Exception{System.out.println("------sendSMS");}public synchronized void sendEmail() throws Exception{System.out.println("------sendEmail");}public void getHello(){System.out.println("------getHello");}}/* @Description: 8锁 @author xialei1 规范拜访,先打印短信还是邮件2 停4秒在短信办法内,先打印短信还是邮件3 新增一般的hello办法,是先打短信还是hello4 当初有两部手机,先打印短信还是邮件5 两个动态同步办法,1部手机,先打印短信还是邮件6 两个动态同步办法,2部手机,先打印短信还是邮件7 1个动态同步办法1个一般同步办法,1部手机,先打印短信还是邮件8 1个动态同步办法1个一般同步办法,2部手机,先打印短信还是邮件 ---------------------------------/public class Lock_8{public static void main(String[] args) throws Exception{Phone phone = new Phone();Phone phone2 = new Phone();new Thread(() -> {try {phone.sendSMS();} catch (Exception e) {e.printStackTrace();}}, "AA").start();Thread.sleep(100);new Thread(() -> {try {phone.sendEmail();//phone.getHello();//phone2.sendEmail();} catch (Exception e) {e.printStackTrace();}}, "BB").start();}} 锁的8个问题(1) 规范拜访,先打印短信还是邮件 (2) 停4秒在短信办法内,先打印短信还是邮件 (3) 一般的hello办法,是先打短信还是hello ...

February 24, 2022 · 1 min · jiezi

关于juc:JUC-中-4-个常用的并发工具类

JUC就是java.util.concurrent包,这个包俗称JUC,外面都是解决并发问题的一些货色。该包的地位位于java上面的rt.jar包上面 4大罕用并发工具类: CountDownLatchCountDownLatch是我目前应用比拟多的类,CountDownLatch初始化时会给定一个计数,而后每次调用countDown() 计数减1, 当计数未达到0之前调用await() 办法会阻塞直到计数减到0; 应用场景:多用于划分工作由多个线程执行,例如:最近写个豆瓣爬虫,须要爬取每个电影的前五页短评,能够划分成五个线程来解决数据。通过latch.await()保障全副实现再返回。     public void latch() throws InterruptedException {        int count= 5;        CountDownLatch latch = new CountDownLatch(count);        for (int x=0;x<count;x++){            new Worker(x*20,latch).start();        }        latch.await();        System.out.println("全副执行结束");    }        class Worker extends Thread{        Integer start;        CountDownLatch latch;        public Worker(Integer start,CountDownLatch latch){            this.start=start;            this.latch=latch;        }        @Override        public void run() {            System.out.println(start+" 已执行");            latch.countDown();        }    }输入如下: 20 已执行0 已执行40 已执行60 已执行80 已执行全副执行结束CyclicBarrier它容许一组线程相互期待,直到达到某个公共屏障点 (common barrier point)也就是阻塞在调用cyclicBarrier.await()的中央。 看上去CyclicBarrier 跟CountDownLatch 性能上相似,java培训在官网doc上CountDownLatch的形容上就阐明了,CountDownLatch 的计数无奈被重置,如果须要重置计数,请思考应用CyclicBarrier。 CyclicBarrier初始时还可增加一个Runnable的参数, 此Runnable在CyclicBarrier的数目达到后,所有其它线程被唤醒前被最初一个进入 CyclicBarrier 的线程执行 应用场景:相似CyclicBarrier,然而 CyclicBarrier提供了几个countdownlatch 没有的办法以应酬更简单的场景,例如: getNumberWaiting() 获取阻塞线程数量, isBroken() 用来晓得阻塞的线程是否被中断等办法。 reset() 将屏障重置为其初始状态。如果所有参与者目前都在屏障处期待,则它们将返回,同时抛出一个 BrokenBarrierException。     public void latch() throws InterruptedException {        int count = 5;        CyclicBarrier cb = new CyclicBarrier(count, new Runnable() {            @Override            public void run() {                System.out.println("全副执行结束");            }        });        ExecutorService executorService = Executors.newFixedThreadPool(count);        while (true){            for (int x=0;x<count;x++){                executorService.execute(new Worker(x,cb));            }        }    }            class Worker extends Thread {        Integer start;        CyclicBarrier cyclicBarrier;        public Worker(Integer start, CyclicBarrier cyclicBarrier) {            this.start = start;            this.cyclicBarrier = cyclicBarrier;        }        @Override        public void run() {            System.out.println(start + " 已执行");            try {                cyclicBarrier.await();            } catch (InterruptedException e) {                e.printStackTrace();            } catch (BrokenBarrierException e) {                e.printStackTrace();            }        }    }输入如下: 0 已执行3 已执行4 已执行2 已执行1 已执行全副执行结束0 已执行1 已执行2 已执行3 已执行4 已执行全副执行结束SemaphoreSemaphore 信号量保护了一个许可集,每次应用时执行acquire()从Semaphore获取许可,如果没有则会阻塞,每次应用完执行release()开释许可。北京java培训应用场景:Semaphore对用于对资源的管制,比方数据连贯无限,应用Semaphore限度拜访数据库的线程数。     public void latch() throws InterruptedException, IOException {        int count = 5;        Semaphore semaphore = new Semaphore(1);        ExecutorService executorService = Executors.newFixedThreadPool(count);            for (int x=0;x<count;x++){                executorService.execute(new Worker(x,semaphore));            }        System.in.read();    }            class Worker extends Thread {        Integer start;        Semaphore semaphore;        public Worker(Integer start, Semaphore semaphore) {            this.start = start;            this.semaphore = semaphore;        }        @Override        public void run() throws IllegalArgumentException {            try {                System.out.println(start + " 筹备执行");                TimeUnit.SECONDS.sleep(1);                semaphore.acquire();                System.out.println(start + " 曾经执行");                semaphore.release();                System.out.println(start + " 曾经开释");            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }输入如下: 0 筹备执行2 筹备执行1 筹备执行3 筹备执行4 筹备执行2 曾经执行2 曾经开释4 曾经执行4 曾经开释1 曾经执行1 曾经开释0 曾经执行0 曾经开释3 曾经执行3 曾经开释ExchangerExchanger 用于两个线程间的数据交换,它提供一个同步点,在这个同步点两个线程能够替换彼此的数据。应用场景:两个线程互相期待处理结果并进行数据传递。     public void latch() throws InterruptedException, IOException {        int count = 5;        Exchanger<String> exchanger = new Exchanger<>();        ExecutorService executorService = Executors.newFixedThreadPool(count);            for (int x=0;x<count;x++){                executorService.execute(new Worker(x,exchanger));            }        System.in.read();    }            class Worker extends Thread {        Integer start;        Exchanger<String>  exchanger;        public Worker(Integer start, Exchanger<String> exchanger) {            this.start = start;            this.exchanger = exchanger;        }        @Override        public void run() throws IllegalArgumentException {            try {                System.out.println(Thread.currentThread().getName() + " 筹备执行");                TimeUnit.SECONDS.sleep(start);                System.out.println(Thread.currentThread().getName() + " 期待替换");                String value = exchanger.exchange(Thread.currentThread().getName());                System.out.println(Thread.currentThread().getName() + " 替换失去数据为:"+value);            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }输入如下: pool-1-thread-1 筹备执行pool-1-thread-1 期待替换pool-1-thread-3 筹备执行pool-1-thread-2 筹备执行pool-1-thread-5 筹备执行pool-1-thread-4 筹备执行pool-1-thread-2 期待替换pool-1-thread-1 替换失去数据为:pool-1-thread-2pool-1-thread-2 替换失去数据为:pool-1-thread-1pool-1-thread-3 期待替换pool-1-thread-4 期待替换pool-1-thread-4 替换失去数据为:pool-1-thread-3pool-1-thread-3 替换失去数据为:pool-1-thread-4pool-1-thread-5 期待替换Exchanger必须成对呈现,否则会像下面代码执行后果那样,pool-1-thread-5始终阻塞期待与其替换数据的线程,为了防止这一景象,能够应用exchange(V x, long timeout, TimeUnit unit)设置最大期待时长。

January 17, 2022 · 1 min · jiezi

关于juc:Java-JUC-CopyOnWriteArrayList-解析

CopyOnWriteArrayList 原理解析介绍在 Java 并发包中的并发 List 只有 CopyOnWriteArrayList,CopyOnWriteArrayList 是一个线程平安的 ArrayList,对其进行的批改操作都是在底层的一个复制的数组(快照)上进行的,也就是应用了写时复制策略。 在 CopyOnWriteArrayList 的类图中,每个 CopyOnWriteArrayList 对象外面有一个 array 数组用来寄存具体的元素,ReentrantLock独占锁来保障同时只有一个线程对 array 进行批改。 如果让咱们本人做一个写时复制的线程平安的 list 咱们会怎么做,有哪些点须要思考? 何时初始化 list,初始化的 list 元素个数为多少,list 是无限大小吗?如何保障线程平安,比方多个线程进行读写时如何保障是线程平安的?如何保障应用迭代器遍历 list 时的数据一致性?上面咱们看一下 CopyOnWriteArrayList 是如何实现的。 次要办法解析初始化在无参构造函数中,默认创立大小为 0 的 Object 数组作为初始值。 public CopyOnWriteArrayList() { setArray(new Object[0]);}有参构造函数: //传入的toCopyIn的正本public CopyOnWriteArrayList(E[] toCopyIn) { setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));}//入参为汇合,复制到list中public CopyOnWriteArrayList(Collection<? extends E> c) { Object[] elements; if (c.getClass() == CopyOnWriteArrayList.class) elements = ((CopyOnWriteArrayList<?>)c).getArray(); else { elements = c.toArray(); // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elements.getClass() != Object[].class) elements = Arrays.copyOf(elements, elements.length, Object[].class); } setArray(elements);}增加元素CopyOnWriteArrayList 中用来增加元素的函数有: ...

January 11, 2022 · 3 min · jiezi

关于juc:Java-并发包原子操作类解析

Java 并发包原子操作类解析前言JUC 包中提供了一些列原子操作类,这些类都是应用非阻塞算法CAS实现的,相比应用锁实现原子性操作在性能上有较大进步。 因为原子性操作的原理都大致相同,本文只解说简略的 AtomicLong 类的原理以及在JDK8中新增的 LongAdder 类原理。 原子变量操作类JUC 并发包中蕴含 AtomicInteger、AtomicLong 和 AtomicBoolean 等原子性操作类,原理大抵相似,接下来咱们看一下 AtomicLong 类。 AtomicLong 是原子性递增或者递加类,外部应用Unsafe来实现,咱们看上面的代码。 public class AtomicLong extends Number implements java.io.Serializable { private static final long serialVersionUID = 1927816293512124184L; //1. 获取Unsafe实例 private static final Unsafe unsafe = Unsafe.getUnsafe(); //2. 寄存变量value的偏移量 private static final long valueOffset; //3. 判断JVM是否反对Long类型无锁CAS static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8(); private static native boolean VMSupportsCS8(); static { try { //4. 获取value在AtomicLong中的偏移量 valueOffset = unsafe.objectFieldOffset (AtomicLong.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } //5. 理论变量值 private volatile long value; public AtomicLong(long initialValue) { value = initialValue; } ......}首先通过Unsafe.getUnsafe()办法获取到 Unsafe 类的实例, ...

January 5, 2022 · 8 min · jiezi

关于juc:Java-JUC-ThreadLocalRandom类解析

ThreadLocalRandom 类解析前言ThreadLocalRandom 类是 JDK7 在JUC包下新增的随机数生成器,它次要解决了 Random 类在多线程下的有余。 本文次要解说为什么须要 ThreadLocalRandom 类,以及该类的实现原理。 Random 类及其局限性首先咱们先理解一下 Random 类。在 JDK7 以前到当初,java.util.Random 类都是应用较为宽泛的随机数生成工具类,而且 java.lang.Math 的随机数生成也是应用的 java.util.Random 类的实例,上面先看看如何应用 Random 类。 public static void main(String[] args) { //1. 创立一个默认种子随机数生成器 Random random = new Random(); //2. 输入10个在0-5之间的随机数(蕴含0,不蕴含5) for (int i = 0; i < 10; i++) { System.out.print(random.nextInt(5)); //3421123432 }}随机数的生成须要一个默认种子,这个种子其实是一个long类型的数字,能够通过在创立 Random 类对象时通过构造函数指定,如果不指定则在默认构造函数外部生成一个默认的值。 种子数只是随机算法的起始数字,和生成的随机数字的区间无关。public Random() { this(seedUniquifier() ^ System.nanoTime());}public Random(long seed) { if (getClass() == Random.class) this.seed = new AtomicLong(initialScramble(seed)); else { // subclass might have overriden setSeed this.seed = new AtomicLong(); setSeed(seed); }}在有了默认种子之后,Random 是如何生成随机数的呢?咱们看一下 nextInt()办法。 ...

January 3, 2022 · 4 min · jiezi