关于多线程:java-手写并发框架一异步查询转同步的-7-种实现方式

40次阅读

共计 15840 个字符,预计需要花费 40 分钟才能阅读完成。

序言

本节将学习一下如何实现异步查问转同步的形式,共计介绍了 7 种常见的实现形式。

思维导图如下:

异步转同步

业务需要

有些接口查问反馈后果是异步返回的,无奈立即获取查问后果。

比方业务开发中咱们调用其余零碎,然而后果的返回的确告诉的。

或者 rpc 实现中,client 调用 server 端,后果也是异步返回的,那么如何同步获取调用后果呢?

  • 失常解决逻辑

触发异步操作,而后传递一个惟一标识。

等到异步后果返回,依据传入的惟一标识,匹配此次后果。

  • 如何转换为同步

失常的利用场景很多,然而有时候不想做数据存储,只是想简略获取调用后果。

即想达到同步操作的后果,怎么办呢?

思路

  1. 发动异步操作
  2. 在异步后果返回之前,始终期待(能够设置超时)
  3. 后果返回之后,异步操作后果对立返回

常见的实现形式

  • 循环期待
  • wait & notify
  • 应用条件锁
  • 应用 CountDownLatch
  • 应用 CyclicBarrier
  • Future
  • Spring EventListener

上面咱们一起来学习下这几种实现形式。

循环期待

阐明

循环期待是最简略的一种实现思路。

咱们调用对方一个申请,在没有后果之前始终循环查问即可。

这个后果能够在内存中,也能够放在 redis 缓存或者 mysql 等数据库中。

代码实现

定义形象父类

为了便于前面的其余几种实现形式对立,咱们首先定义一个形象父类。

/**
 * 形象查问父类
 * @author binbin.hou
 * @since 1.0.0
 */
public abstract class AbstractQuery {private static final Log log = LogFactory.getLog(AbstractQuery.class);

    protected String result;

    public void asyncToSync() {startQuery();
        new Thread(new Runnable() {public void run() {remoteCall();
            }
        }).start();
        endQuery();}

    protected void startQuery() {log.info("开始查问...");
    }

    /**
     * 近程调用
     */
    protected void remoteCall() {
        try {log.info("近程调用开始");
            TimeUnit.SECONDS.sleep(5);
            result = "success";
            log.info("近程调用完结");
        } catch (InterruptedException e) {log.error("近程调用失败", e);
        }
    }

    /**
     * 查问完结
     */
    protected void endQuery() {log.info("实现查问,后果为:" + result);
    }

}

代码实现

实现还是非常简单的,在没有后果之前始终循环。

TimeUnit.MILLISECONDS.sleep(10); 这里循环期待的小睡一会儿是比拟重要的,防止 cpu 飙升,也能够升高为 1ms,依据本人的业务调整即可。

/**
 * 循环期待
 * @author binbin.hou
 * @since 1.0.0
 */
public class LoopQuery extends AbstractQuery {private static final Log log = LogFactory.getLog(LoopQuery.class);

    @Override
    protected void endQuery() {
        try {while (StringUtil.isEmpty(result)) {
                // 循环期待一下
                TimeUnit.MILLISECONDS.sleep(10);
            }

            // 获取后果

            log.info("实现查问,后果为:" + result);
        } catch (InterruptedException e) {e.printStackTrace();
        }
    }

}

测试

LoopQuery loopQuery = new LoopQuery();
loopQuery.asyncToSync();
  • 日志
[INFO] [2020-10-08 09:50:43.330] [main] [c.g.h.s.t.d.AbstractQuery.startQuery] - 开始查问...
[INFO] [2020-10-08 09:50:43.331] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 近程调用开始
[INFO] [2020-10-08 09:50:48.334] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 近程调用完结
[INFO] [2020-10-08 09:50:48.343] [main] [c.g.h.s.t.d.LoopQuery.endQuery] - 实现查问,后果为:success

这里能够看到近程调用是 Thread-0 线程执行的,近程调用的耗时为 5S。

超时个性

为什么须要超时工夫

下面的实现存在一个问题,那就是循环期待没有超时工夫。

咱们的一个网络申请,可能存在失败,也可能对方收到申请之后没有正确处理。

所以如果咱们始终期待,可能永远也没有后果,或者很久之后才有后果。这在业务上是不可忍耐的,所以须要增加一个超时工夫。

代码实现

/**
 * 循环期待 - 蕴含超时工夫
 * @author binbin.hou
 * @since 1.0.0
 */
public class LoopTimeoutQuery extends AbstractQuery {private static final Log log = LogFactory.getLog(LoopTimeoutQuery.class);

    /**
     * 超时工夫
     */
    private long timeoutMills = 3000;

    public LoopTimeoutQuery() {}

    public LoopTimeoutQuery(long timeoutMills) {this.timeoutMills = timeoutMills;}

    @Override
    protected void endQuery() {
        try {final long endTimeMills = System.currentTimeMillis() + timeoutMills;

            while (StringUtil.isEmpty(result)) {
                // 超时判断
                if(System.currentTimeMillis() >= endTimeMills) {throw new RuntimeException("申请超时");
                }

                // 循环期待一下
                TimeUnit.MILLISECONDS.sleep(10);
            }

            // 获取后果

            log.info("实现查问,后果为:" + result);
        } catch (InterruptedException e) {e.printStackTrace();
        }
    }

}

测试

LoopTimeoutQuery loopQuery = new LoopTimeoutQuery();
loopQuery.asyncToSync();

日志如下:

[INFO] [2020-10-08 10:04:58.091] [main] [c.g.h.s.t.d.AbstractQuery.startQuery] - 开始查问...
[INFO] [2020-10-08 10:04:58.092] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 近程调用开始
Exception in thread "main" java.lang.RuntimeException: 申请超时
    at com.github.houbb.sync.test.demo.LoopTimeoutQuery.endQuery(LoopTimeoutQuery.java:38)
    at com.github.houbb.sync.test.demo.AbstractQuery.asyncToSync(AbstractQuery.java:26)
    at com.github.houbb.sync.test.demo.LoopTimeoutQuery.main(LoopTimeoutQuery.java:55)
[INFO] [2020-10-08 10:05:03.097] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 近程调用完结

超时工夫是能够设定的,平时开发中能够依据本人的响应工夫设置。

如果申请超时,思考对应的兜底计划。

基于 wait() & notifyAll()

简介

实际上 loop 循环还是比拟耗费性能的,对于这种期待个性, jdk 实际上为咱们封装了多种个性。

比方最常见的 wait() 进入期待,notifyAll() 唤醒期待的组合形式。

这个同时也是阻塞队列的实现思维,阻塞队列咱们就不介绍了,咱们来看一下 wait+notify 的实现形式。

java 实现

package com.github.houbb.sync.test.demo;

import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;

/**
 * wait+notify 实现
 * @author binbin.hou
 * @since 1.0.0
 */
public class WaitNotifyQuery extends AbstractQuery {private static final Log log = LogFactory.getLog(WaitNotifyQuery.class);

    /**
     * 申明对象
     */
    private final Object lock = new Object();

    @Override
    protected void remoteCall() {super.remoteCall();
        synchronized (lock) {log.info("近程线程执行实现,唤醒所有期待。");
            lock.notifyAll();}
    }

    @Override
    protected void endQuery() {
        try {
            // 期待 10s
            synchronized (lock) {log.info("主线程进入期待");
                lock.wait(10 * 1000);
            }
        } catch (InterruptedException e) {e.printStackTrace();
        }

        super.endQuery();}

    public static void main(String[] args) {WaitNotifyQuery query = new WaitNotifyQuery();
        query.asyncToSync();}

}

留神:编程时须要应用 synchronized 保障锁的持有者线程平安,不然会报错。

测试

日志如下:

[INFO] [2020-10-08 11:05:50.769] [main] [c.g.h.s.t.d.AbstractQuery.startQuery] - 开始查问...
[INFO] [2020-10-08 11:05:50.770] [main] [c.g.h.s.t.d.WaitNotifyQuery.endQuery] - 主线程进入期待
[INFO] [2020-10-08 11:05:50.770] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 近程调用开始
[INFO] [2020-10-08 11:05:55.772] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 近程调用完结
[INFO] [2020-10-08 11:05:55.773] [Thread-0] [c.g.h.s.t.d.WaitNotifyQuery.remoteCall] - 近程线程执行实现,唤醒所有期待。[INFO] [2020-10-08 11:05:55.773] [main] [c.g.h.s.t.d.AbstractQuery.endQuery] - 实现查问,后果为:success

基于条件锁的实现

条件锁简介

如果你想编写一个含有多个条件谓词的并发对象, 或者你想取得比条件队列的可见性之外更多的控制权, 那么显式的 Lock 和 Condition 的实现类提供了一个 比外部锁和条件队列更加灵便的抉择。

如同 Lock 提供了比外部加锁要丰盛得多的特色集一样,Condition 也提供了比外部条件队列要丰盛得多的特色集:

每个锁能够有多个期待集(因 await 挂起的线程的汇合)、可中断 / 不可中断的条件期待、基于时限的期待以及偏心 / 非偏心队列之间的抉择.

Condition 介绍

注意事项:

wait、notify 和 notifyAll 在 Condition 对象中的对等体是 await、signal 和 signalAll.

然而,Condition 继承与 Object, 这意味着它也有 wait 和 notify 办法.

肯定要确保应用了正确的版本–await 和 signal!

java 实现

为了演示简略,咱们间接抉择可重入锁即可。

一个 Condition 和一个独自的 Lock 相关联, 就像条件队列和独自的外部锁相关联一样;

调用与 Condition 相关联的 Lock 的 Lock.newCondition 办法, 能够创立一个 Condition.

package com.github.houbb.sync.test.demo;

import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 条件锁实现
 * @author binbin.hou
 * @since 1.0.0
 */
public class LockConditionQuery extends AbstractQuery {private static final Log log = LogFactory.getLog(LockConditionQuery.class);

    private final Lock lock = new ReentrantLock();

    private final Condition condition = lock.newCondition();

    @Override
    protected void remoteCall() {lock.lock();
        try{super.remoteCall();

            log.info("近程线程执行实现,唤醒所有期待线程。");
            condition.signalAll();} finally {lock.unlock();
        }

    }

    @Override
    protected void endQuery() {lock.lock();
        try{
            // 期待
            log.info("主线程进入期待");

            condition.await();

            super.endQuery();} catch (InterruptedException e) {e.printStackTrace();
        } finally {lock.unlock();
        }
    }

    public static void main(String[] args) {LockConditionQuery query = new LockConditionQuery();
        query.asyncToSync();}

}

实现也比较简单,咱们在办法进入,调用 lock.lock() 加锁,finally 中调用 lock.unlock() 开释锁。

condition.await(); 进入期待;condition.signalAll(); 唤醒所有期待线程。

测试日志

[INFO] [2020-10-08 12:33:40.985] [main] [c.g.h.s.t.d.AbstractQuery.startQuery] - 开始查问...
[INFO] [2020-10-08 12:33:40.986] [main] [c.g.h.s.t.d.LockConditionQuery.endQuery] - 主线程进入期待
[INFO] [2020-10-08 12:33:40.987] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 近程调用开始
[INFO] [2020-10-08 12:33:45.990] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 近程调用完结
[INFO] [2020-10-08 12:33:45.991] [Thread-0] [c.g.h.s.t.d.LockConditionQuery.remoteCall] - 近程线程执行实现,唤醒所有期待线程。[INFO] [2020-10-08 12:33:45.993] [main] [c.g.h.s.t.d.AbstractQuery.endQuery] - 实现查问,后果为:success

CountDownLatch 闭锁实现

CountDownLatch/Future/CyclicBarrier 这三个都是 jdk 为咱们提供的同步工具类,咱们此处只做简略介绍。

详情参见:

JCIP-19- 同步工具类。闭锁 / 栅栏 / 信号量 / 阻塞队列 /FutureTask

CountDownLatch 简介

闭锁是一种同步工具类,能够延迟线程的进度直到其达到终止状态。

闭锁的作用相当于一扇门:在闭锁达到完结状态之前,这扇门始终是敞开的,并且没有任何线程能通过,当达到完结状态时,这扇门会关上并容许所有的线程通过。

当闭锁达到完结状态后,将不会再扭转状态,因而这扇门将永远放弃关上状态。

闭锁能够用来确保某些流动直到其它流动都实现后才继续执行。

java 代码实现

import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * CountDownLatch 实现
 * @author binbin.hou
 * @since 1.0.0
 */
public class CountDownLatchQuery extends AbstractQuery {private static final Log log = LogFactory.getLog(CountDownLatchQuery.class);

    /**
     * 闭锁
     * 调用 1 次,后续办法即可通行。*/
    private final CountDownLatch countDownLatch = new CountDownLatch(1);

    @Override
    protected void remoteCall() {super.remoteCall();

        // 调用一次闭锁
        countDownLatch.countDown();}

    @Override
    protected void endQuery() {
        try {//            countDownLatch.await();
            countDownLatch.await(10, TimeUnit.SECONDS);

            log.info("实现查问,后果为:" + result);
        } catch (InterruptedException e) {e.printStackTrace();
        }
    }

    public static void main(String[] args) {CountDownLatchQuery loopQuery = new CountDownLatchQuery();
        loopQuery.asyncToSync();}

}

咱们在返回后果之前调用 countDownLatch.await(10, TimeUnit.SECONDS); 进行期待,这里能够指定超时工夫。

remoteCall() 近程实现后,执行一下 countDownLatch.countDown();,进而能够让程序继续执行上来。

测试

代码

CountDownLatchQuery loopQuery = new CountDownLatchQuery();
loopQuery.asyncToSync();

日志

[INFO] [2020-10-08 10:24:03.348] [main] [c.g.h.s.t.d.AbstractQuery.startQuery] - 开始查问...
[INFO] [2020-10-08 10:24:03.350] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 近程调用开始
[INFO] [2020-10-08 10:24:08.353] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 近程调用完结
[INFO] [2020-10-08 10:24:08.354] [main] [c.g.h.s.t.d.CountDownLatchQuery.endQuery] - 实现查问,后果为:success

jdk 提供的闭锁性能还是十分的不便的。

CyclicBarrier 栅栏

简介

栅栏(Barrier)相似于闭锁,它能阻塞一组线程直到某个事件产生[CPJ 4.4.3]。闭锁是一次性对象,一旦进入最终状态,就不能被重置了。

栅栏与闭锁的要害区别在于,所有线程必须同时达到栅栏地位,能力继续执行。闭锁用于期待事件,而栅栏用于期待其余线程。

java 实现

package com.github.houbb.sync.test.demo;

import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * CyclicBarrier 实现
 * @author binbin.hou
 * @since 1.0.0
 */
public class CyclicBarrierQuery extends AbstractQuery {private static final Log log = LogFactory.getLog(CyclicBarrierQuery.class);

    private CyclicBarrier cyclicBarrier = new CyclicBarrier(2);

    @Override
    protected void remoteCall() {super.remoteCall();

        try {cyclicBarrier.await();
            log.info("近程调用进入期待");
        } catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();
        }
    }

    @Override
    protected void endQuery() {
        try {cyclicBarrier.await();
            log.info("主线程进入期待");
        } catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();
        }

        super.endQuery();}

}

测试

代码

public static void main(String[] args) {CyclicBarrierQuery cyclicBarrierQuery = new CyclicBarrierQuery();
    cyclicBarrierQuery.asyncToSync();}

日志

[INFO] [2020-10-08 10:39:00.890] [main] [c.g.h.s.t.d.AbstractQuery.startQuery] - 开始查问...
[INFO] [2020-10-08 10:39:00.892] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 近程调用开始
[INFO] [2020-10-08 10:39:05.894] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 近程调用完结
[INFO] [2020-10-08 10:39:05.895] [Thread-0] [c.g.h.s.t.d.CyclicBarrierQuery.remoteCall] - 近程调用进入期待
[INFO] [2020-10-08 10:39:05.895] [main] [c.g.h.s.t.d.CyclicBarrierQuery.endQuery] - 主线程进入期待
[INFO] [2020-10-08 10:39:05.896] [main] [c.g.h.s.t.d.AbstractQuery.endQuery] - 实现查问,后果为:success

能够看出近程线程 Thread-0 执行完之后就进入期待,此时主线程调用,而后也进入期待。

等主线程 endQuery 期待时,就满足了两个线程同时期待,而后执行就完结了。

基于 Future 实现

Future 简介

Future 模式能够这样来形容:我有一个工作,提交给了 Future,Future 替我实现这个工作。期间我本人能够去做任何想做的事件。一段时间之后,我就便能够从 Future 那儿取出后果。就相当于下了一张订货单,一段时间后能够拿着提订单来提货,这期间能够干别的任何事件。其中 Future 接口就是订货单,真正解决订单的是 Executor 类,它依据 Future 接口的要求来生产产品。

Future 接口提供办法来检测工作是否被执行完,期待工作执行完取得后果,也能够设置工作执行的超时工夫。这个设置超时的办法就是实现 Java 程序执行超时的要害。

具体介绍:

JCIP-26-Executor Future FutureTask

java 代码实现

采纳 Future 返回和以前的实现差别较大,咱们间接覆写以前的办法即可。

import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;

import java.util.concurrent.*;

/**
 * Future 实现
 * @author binbin.hou
 * @since 1.0.0
 */
public class FutureQuery extends AbstractQuery {private static final Log log = LogFactory.getLog(FutureQuery.class);

    private final ExecutorService executorService = Executors.newSingleThreadExecutor();

    @Override
    public void asyncToSync() {
        //1. 开始调用
        super.startQuery();

        //2. 近程调用
        Future<String> stringFuture = remoteCallFuture();

        //3. 实现后果
        try {String result = stringFuture.get(10, TimeUnit.SECONDS);
            log.info("调用后果:{}", result);
        } catch (InterruptedException | TimeoutException | ExecutionException e) {e.printStackTrace();
        }
    }

    /**
     * 近程调用
     * @return Future 信息
     */
    private Future<String> remoteCallFuture() {FutureTask<String> futureTask = new FutureTask<>(new Callable<String>() {
            @Override
            public String call() throws Exception {log.info("开始异步调用");
                TimeUnit.SECONDS.sleep(5);
                log.info("实现异步调用");
                return "success";
            }
        });

        executorService.submit(futureTask);
        // 敞开线程池
        executorService.shutdown();
        return futureTask;
    }

    public static void main(String[] args) {FutureQuery query = new FutureQuery();
        query.asyncToSync();}

}

近程调用执行时,是一个 FutureTask,而后提交到线程池去执行。

获取后果的时候,stringFuture.get(10, TimeUnit.SECONDS) 能够指定获取的超时工夫。

日志

测试日志如下:

[INFO] [2020-10-08 12:52:05.175] [main] [c.g.h.s.t.d.AbstractQuery.startQuery] - 开始查问...
[INFO] [2020-10-08 12:52:05.177] [pool-1-thread-1] [c.g.h.s.t.d.FutureQuery.call] - 开始异步调用
[INFO] [2020-10-08 12:52:10.181] [pool-1-thread-1] [c.g.h.s.t.d.FutureQuery.call] - 实现异步调用
[INFO] [2020-10-08 12:52:10.185] [main] [c.g.h.s.t.d.FutureQuery.asyncToSync] - 调用后果:success

Spring EventListener

spring 事件监听器模式

对于一件事件实现的后果调用,应用观察者模式是非常适合的。

spring 为咱们提供了比拟弱小的监听机制,此处演示下联合 spring 应用的例子。

ps: 这个例子是 2 年前的本人写的例子了,此处为了整个系列的完整性,间接搬过去作为补充。

代码实现

  • BookingCreatedEvent.java

定义一个传输属性的对象。

public class BookingCreatedEvent extends ApplicationEvent {

    private static final long serialVersionUID = -1387078212317348344L;

    private String info;

    public BookingCreatedEvent(Object source) {super(source);
    }

    public BookingCreatedEvent(Object source, String info) {super(source);
        this.info = info;
    }

    public String getInfo() {return info;}
}
  • BookingService.java

阐明:当 this.context.publishEvent(bookingCreatedEvent); 触发时,
会被 @EventListener 指定的办法监听到。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class BookingService {

    @Autowired
    private ApplicationContext context;

    private volatile BookingCreatedEvent bookingCreatedEvent;

    /**
     * 异步转同步查问
     * @param info
     * @return
     */
    public String asyncQuery(final String info) {query(info);

        new Thread(new Runnable() {
            @Override
            public void run() {remoteCallback(info);
            }
        }).start();

        while(bookingCreatedEvent == null) {
            //.. 空循环
            // 短暂期待。try {TimeUnit.MILLISECONDS.sleep(1);
            } catch (InterruptedException e) {//...}
            //2. 应用两个独自的 event...

        }

        final String result = bookingCreatedEvent.getInfo();
        bookingCreatedEvent = null;
        return result;
    }

    @EventListener
    public void onApplicationEvent(BookingCreatedEvent bookingCreatedEvent) {System.out.println("监听到近程的信息:" + bookingCreatedEvent.getInfo());
        this.bookingCreatedEvent = bookingCreatedEvent;
        System.out.println("监听到近程音讯后:" + this.bookingCreatedEvent.getInfo());
    }

    /**
     * 执行查问
     * @param info
     */
    public void query(final String info) {System.out.println("开始查问:" + info);
    }

    /**
     * 近程回调
     * @param info
     */
    public void remoteCallback(final String info) {System.out.println("近程回调开始:" + info);

        try {TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {e.printStackTrace();
        }

        // 重发后果事件
        String result = info + "-result";
        BookingCreatedEvent bookingCreatedEvent = new BookingCreatedEvent(this, result);
        // 触发 event
        this.context.publishEvent(bookingCreatedEvent);
    }
}
  • 测试方法
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class BookServiceTest {

    @Autowired
    private BookingService bookingService;

    @Test
    public void asyncQueryTest() {bookingService.asyncQuery("1234");
    }

}
  • 日志
2018-08-10 18:27:05.958  INFO  [main] com.github.houbb.spring.lean.core.ioc.event.BookingService:84 - 开始查问:1234
2018-08-10 18:27:05.959  INFO  [Thread-2] com.github.houbb.spring.lean.core.ioc.event.BookingService:93 - 近程回调开始:1234
接管到信息: 1234-result
2018-08-10 18:27:07.964  INFO  [Thread-2] com.github.houbb.spring.lean.core.ioc.event.BookingService:73 - 监听到近程的信息: 1234-result
2018-08-10 18:27:07.964  INFO  [Thread-2] com.github.houbb.spring.lean.core.ioc.event.BookingService:75 - 监听到近程音讯后: 1234-result
2018-08-10 18:27:07.964  INFO  [Thread-2] com.github.houbb.spring.lean.core.ioc.event.BookingService:106 - 曾经触发 event
2018-08-10 18:27:07.964  INFO  [main] com.github.houbb.spring.lean.core.ioc.event.BookingService:67 - 查问后果: 1234-result
2018-08-10 18:27:07.968  INFO  [Thread-1] org.springframework.context.support.GenericApplicationContext:993 - Closing org.springframework.context.support.GenericApplicationContext@5cee5251: startup date [Fri Aug 10 18:27:05 CST 2018]; root of context hierarchy

小结

本文共计介绍了 7 种异步转同步的形式,实际上思维都是一样的。

在异步执行实现前期待,执行实现后唤醒期待即可。

当然我写本文除了总结以上几种形式以外,还想为后续写一个异步转同步的工具提供根底。

下一节咱们将一起学习下如何将这个性能封装为一个同步转换框架,感兴趣的能够关注一下,便于实时接管最新内容。

感觉本文对你有帮忙的话,欢送点赞评论珍藏转发一波。你的激励,是我最大的能源~

不晓得你有哪些播种呢?或者有其余更多的想法,欢送留言区和我一起探讨,期待与你的思考相遇。

代码地址

为了便于学习,文中的所有例子都曾经开源:

实现 1-6:sync

loop

countdownlatch

spring-event-listener

正文完
 0