java同步获取异步任务结果JavaPromise

同步获取异步任务结果

思路:首先从jdk提供的框架和代码入手,然后再自己定义一个,

原创qq作者:855189478

1、CountDownLatch

使用同步框架可以实现同步,但是不能获取到异步的结果

参考代码如下:

import java.util.concurrent.CountDownLatch;

public class FutureTest {
    public static void main(String[] args) throws Exception {
        CountDownLatch countDownLatch = new CountDownLatch(1);
        new Thread(()->{
            try {
                //线程等待模拟异步耗时任务,比如io(socket有关)
                Thread.sleep(2000);
                //当信号量减少为0,则await被唤醒且信号量
                countDownLatch.countDown();
                countDownLatch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        //阻塞了,同步等待异步执行完成。
        countDownLatch.await();
        System.out.println("异步任务执行完成");
    }
}

/**
关于CountDownLatch使用
1、构造函数传入初始信号量
2、通过countDown来降低1个信号量,当信号量为0时await就会被唤醒。
3、使用场景:一个阶段多任务完成后再进入下一个阶段,即阶段划分。
   比如多个线程执行完才执行某段代码
   
4、  若在调用await()时 信号量不为0,则await阻塞
     若调用await()是,信号量已经为0,则不阻塞
     当信号量为0时,调用countDown无任何影响,因为信号量最少是0。
*/

2、FutureTask

将异步任务封装到FutureTask中交由线程池执行

学习FutureTask(更多参考Future实现类)

实例一:

//错误用法
FutureTask<String>  task=new FutureTask(()->{
    System.out.println(Thread.currentThread().getName());
    Thread.sleep(2000);
    return "结果";
});
task.run();
//如果不调用task.run(); 则task.get()会一直阻塞
//因为任务未执行所以内部状态未变化,run后状态变化不阻塞,但是都是main线程执行的。
System.out.println(task.get());

实例二、

//run方法通常线程池会自动调用,就提交线程池
 ExecutorService executorService = Executors.newFixedThreadPool(1);
 FutureTask<String>  task=new FutureTask(()->{
     System.out.println(Thread.currentThread().getName());
     Thread.sleep(2000);
     return "结果";
 });
//FutureTask实现了Runnable接口,线程池自动调用run方法,
//从而状态改变后task.get()解除阻塞,同时获取到结果
 executorService.submit(callable);
 System.out.println(task.get());

//线程池可以提交Runnable和Callable 子类

Callable实例补充:

ExecutorService executorService = Executors.newFixedThreadPool(1);
Callable<String>  callable = new Callable<String>() {
    @Override
    public String call() throws Exception {
        System.out.println(Thread.currentThread().getName());
        Thread.sleep(2000);
        return "结果";
    }
};
Future f= executorService.submit(callable);
System.out.println(f.get());

3、自己实现

Future方式是将耗时任务提交到线程池处理,和我们实现获取异步任务结果还是有区别的:

1、当我们需要同步获取回调函数中的结果使用Future就不合适了。

2、当我们提交同步任务到线程池,Future比较合适。

3、接下来实现:同步获取回调函数中的返回结果。

需求来源:

//实例说明,如下是zk连接,异步回调,getNewClient执行完需要通过回调才知道连接建立是否成功还是异常。
//思考:如何保证getNewClient执行结束可以获取到连接结果?

/**      
      <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-client</artifactId>
            <version>4.0.0</version>
            </dependency>
  */     
private CuratorFramework getNewClient() {
    //间隔5秒重试3次
    RetryPolicy retryPolicy = new ExponentialBackoffRetry(5000, 3);
    CuratorFramework client = CuratorFrameworkFactory.builder()
        .connectString(this.connectionUrl)
        .retryPolicy(retryPolicy)
        .namespace("chat")
        .sessionTimeoutMs(3000)
        .build();
    
    client.getUnhandledErrorListenable().addListener((message, ex) -> {
        System.err.println("error=" + message);
        ex.printStackTrace();
    
        promsie.tryFailure(ex);
    });
    client.getConnectionStateListenable().addListener((c, newState) -> {
        System.out.println("state=" + newState);
        if (newState== ConnectionState.CONNECTED){
            promsie.trySuccess("zk获取连接成功");
        }
    });
    client.start();
    //
}

同步获取回调结果:

实现逻辑:方法返回前先阻塞,等回调执行完成再返回。

如果 client.start();能返回Future,我们只需要Future.get()就可以,但是实际没有,

可能因为回调函数多个,我们需求不一样,需要根据自己需求定制。

实现参考:使用过netty的应该知道,netty中定义了ChannelPromise接口来实现异步返回结果和异常。

第一版实现代码:

//说明:如果阅读有困难,将SyncProimseListener部分忽略

package promise;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

public class SyncPromise<V> {

    private static final Logger logger = LoggerFactory.getLogger(SyncPromise.class);

    private Object lock = new Object();
    //用于不同线程之间传递数据,即tryXX到get的传递
    private volatile Object result;
    private static final Object SUCCESS = new Object();

    //用于无锁化处理
    private static final AtomicReferenceFieldUpdater<SyncPromise, Object> RESULT_UPDATER =
            AtomicReferenceFieldUpdater.newUpdater(SyncPromise.class, Object.class, "result");

    private final ArrayList<SyncProimseListener> notifyListeners = new ArrayList<>();

    /**
     * 设置状态,并通知wait线程(get引起),无异常
     *
     * @param result 可以设置一个状态数据
     */
    public boolean trySuccess(V result) {
        return setValue0(result==null?SUCCESS:result);
    }

    /**
     *
     * @param cause  对应get时返回的异常
     * @return  true:set和listener首次执行完成,false:失败未执行
     */
    public boolean tryFailure(Throwable cause) {
        //代码优化:采用无锁处理 result的赋值
        if (cause==null){
            throw new NullPointerException("cause");
        }
        return setValue0(cause);
    }

    private boolean setValue0(Object objResult){
        if (RESULT_UPDATER.compareAndSet(this, null, objResult)){
            //确保只有一次机会来唤醒get阻塞,失败唤醒。
            if (checkNotifyWaiters()) {
                notifyListeners();
            }
            return true;
        }
        return false;
    }


    public boolean isDone() {
        return isDone0(result);
    }


    private boolean isDone0(Object result) {
        return result != null;
    }

    private short waiters;

    private void incWaiters() {
        if (waiters == Short.MAX_VALUE) {
            throw new IllegalStateException("too many waiters: " + this);
        }
        ++waiters;
    }

    private void decWaiters() {
        --waiters;
    }

    /**
     * 唤醒等待的线程(get引起的等待)
     * @return {@code true} if there are listeners
     */
    private synchronized boolean checkNotifyWaiters() {
        if (waiters > 0) {
            notifyAll();
        }
        return this.notifyListeners.size() > 0;
    }

    private void notifyListeners() {
        synchronized (this) {
            if (this.notifyListeners == null) {
                return;
            }
            for (SyncProimseListener l : this.notifyListeners) {
                try {
                    l.operationComplete(this);
                } catch (Exception e) {
                    if (logger.isWarnEnabled()) {
                        logger.warn("An exception was thrown by " + 
                                    l.getClass().getName() + ".operationComplete()", e);
                    }
                }
            }
        }
    }

    public V get() throws InterruptedException, ExecutionException {
        Object result = this.result;
        //等待完成的处理
        if (!isDone0(result)) {
            await();
            result = this.result;
        }
        //正确完成的处理  success
        if (result == SUCCESS) {
            return null;
        }
        //错误完成的处理,cause
        Throwable cause = cause0(result);
        if (cause == null) {
            return (V) result;
        }
        //返回tryFailure设置的异常
        throw new ExecutionException(cause);
    }

    public Throwable cause() {
        return cause0(result);
    }


    private Throwable cause0(Object result) {
        if (!(result instanceof Throwable)) {
            return null;
        }
        return (Throwable) result;
    }

    private SyncPromise<V> await() throws InterruptedException {
        if (isDone()) {
            return this;
        }

        if (Thread.interrupted()) {
            throw new InterruptedException(toString());
        }

        synchronized (this) {
            while (!isDone()) {
                incWaiters();
                try {
                    wait();
                } finally {
                    decWaiters();
                }
            }
        }
        return this;
    }

    public void addListener(SyncProimseListener<SyncPromise> listener) {
        if (listener==null){
            throw new NullPointerException("listener");
        }
        synchronized (this) {
            this.notifyListeners.add(listener);
        }
    }

    public void removeListener(SyncProimseListener<SyncPromise> listener) {
        synchronized (lock) {
            for (int i = 0; i < this.notifyListeners.size(); i++) {
                if (listener == this.notifyListeners.get(i)) {
                    this.notifyListeners.remove(listener);
                    break;
                }
            }
        }
    }

}
/**
补充说明:
 1、代码看起来长,实际原理是:
     get()方法会阻塞线程可以多次调用,trySuccess或tryFailure来唤醒阻塞的多个线程。
     get()返回结果或者抛出异常,从而实现可以获取异步回调中的结果,实现方法同步。
     

*/

第一版调用实例:

import java.util.concurrent.ExecutionException;

public class TestPromise {
    public static void main(String[] args) {
        //通过SyncPromise同步实现获取回到结果。
        SyncPromise<String> p = new SyncPromise();

        //用单独线程模拟回调
        new Thread(()->{
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //执行后会唤醒由于get()导致的线程等待,也就是就是Object.notifyAll( )
            p.trySuccess("成功");
            //这个导致get()抛出异常方式
            //p.tryFailure(new Exception("test"));

        }).start();

        try {
            //阻塞等待被唤醒,并返回结果
            String s= p.get();

        } catch (InterruptedException e) {
            //有阻塞就可能有中断异常
            e.printStackTrace();
        } catch (ExecutionException e) {
            //自己处理
            e.printStackTrace();
        }
    }
}

第二版:代码优化

SyncPromise中方法太多,私有共有混到一块,我们用内部类来调整下。

public class SyncPromise<V> {
    private static final Logger logger = LoggerFactory.getLogger(SyncPromise.class);

    //用户未传入时的替代参数
    private static final Object SUCCESS = new Object();
    //用于不同线程之间传递数据,即tryXX到get的传递
    private volatile Object result;
    //用于无锁化处理
    private static final AtomicReferenceFieldUpdater<SyncPromise, Object> RESULT_UPDATER =
            AtomicReferenceFieldUpdater.newUpdater(SyncPromise.class, Object.class, "result");


    private Inner<V> inner;

    public SyncPromise() {
        inner = new Inner<>();
    }

    /**
     * 设置状态,并通知wait线程(get引起),无异常
     *
     * @param result 可以设置一个状态数据
     */
    public boolean trySuccess(V result) {
        return inner.setValue0(result == null ? SUCCESS : result);
    }

    /**
     * @param cause 对应get时返回的异常
     * @return true:set和listener首次执行完成,false:失败未执行
     */
    public boolean tryFailure(Throwable cause) {
        //代码优化:采用无锁处理 result的赋值
        if (cause == null) {
            throw new NullPointerException("cause");
        }
        return inner.setValue0(cause);
    }

    public V get() throws InterruptedException, ExecutionException {
        Object result = this.result;
        //等待完成的处理
        if (!inner.isDone0(result)) {
            inner.await();
            result = this.result;
        }
        //正确完成的处理  success
        if (result == SUCCESS) {
            return null;
        }
        //错误完成的处理,cause
        Throwable cause = inner.cause0(result);
        if (cause == null) {
            return (V) result;
        }
        //返回tryFailure设置的异常
        throw new ExecutionException(cause);
    }

   //以下是内部类,方法和属性都不公开 ,调用方法参考上边即可
    

    final class Inner<V> {


        private Object listenerLock = new Object();

        //复合操作还是用自定义锁
        //private final List<SyncProimseListener> notifyListeners = Collections.synchronizedList(new ArrayList<SyncProimseListener>());
        private final List<SyncProimseListener> notifyListeners = new ArrayList<SyncProimseListener>();


        private boolean setValue0(Object objResult) {
            if (RESULT_UPDATER.compareAndSet(SyncPromise.this, null, objResult)) {
                //确保只有一次机会来唤醒get阻塞,失败唤醒。
                if (checkNotifyWaiters()) {
                    notifyListeners();
                }
                return true;
            }
            return false;
        }


        public boolean isDone() {
            return isDone0(result);
        }


        private boolean isDone0(Object result) {
            return result != null;
        }

        private short waiters;

        private void incWaiters() {
            if (waiters == Short.MAX_VALUE) {
                throw new IllegalStateException("too many waiters: " + this);
            }
            ++waiters;
        }

        private void decWaiters() {
            --waiters;
        }

        /**
         * 唤醒等待的线程(get引起的等待)
         *
         * @return {@code true} if there are listeners
         */
        private synchronized boolean checkNotifyWaiters() {
            if (waiters > 0) {
                notifyAll();
            }
            return this.notifyListeners.size() > 0;
        }

        private void notifyListeners() {
            synchronized (this) {
                if (this.notifyListeners == null) {
                    return;
                }
                for (SyncProimseListener l : this.notifyListeners) {
                    try {
                        l.operationComplete(this);
                    } catch (Exception e) {
                        if (logger.isWarnEnabled()) {
                            logger.warn("An exception was thrown by " + l.getClass().getName() + ".operationComplete()", e);
                        }
                    }
                }
            }
        }


        public Throwable cause() {
            return cause0(result);
        }


        private Throwable cause0(Object result) {
            if (!(result instanceof Throwable)) {
                return null;
            }
            return (Throwable) result;
        }

        private void await() throws InterruptedException {
            if (isDone()) {
                return;
            }

            if (Thread.interrupted()) {
                throw new InterruptedException(toString());
            }

            synchronized (this) {
                while (!isDone()) {
                    incWaiters();
                    try {
                        System.out.println(Thread.currentThread().getName());
                        wait();
                    } finally {
                        decWaiters();
                    }
                }
            }
        }

        public void addListener(SyncProimseListener<SyncPromise> listener) {

            if (listener == null) {
                throw new NullPointerException("listener");
            }
            synchronized (listenerLock) {
                this.notifyListeners.add(listener);
            }
        }

        public void removeListener(SyncProimseListener<SyncPromise> listener) {
            synchronized (listenerLock) {
                for (int i = 0; i < this.notifyListeners.size(); i++) {
                    if (listener == this.notifyListeners.get(i)) {
                        this.notifyListeners.remove(listener);
                        break;
                    }
                }
            }
        }

    }
}

SyncProimseListener

public interface SyncProimseListener<SyncPromise> {
    void operationComplete(SyncPromise syncPromise) throws Exception;
}

第二版调用:

调用方式和第一版完全一样。

关于第二版:
1、trySuccess和tryFailure 只能执行一次,因为变量只能设置一次。
2、get()可以在多个线程调用,由tryxx来唤醒。
3、listener使用场景:
   listener调用关键代码:
        private boolean setValue0(Object objResult) {
            if (RESULT_UPDATER.compareAndSet(SyncPromise.this, null, objResult)) {
                //确保只有一次机会来唤醒get阻塞,失败唤醒。
                if (checkNotifyWaiters()) {
                    notifyListeners();
                }
                return true;
            }
            return false;
        }
        
  //可以自定义来实现具体需要
  1)比如首次try不调用listener,后续try调用触发listener
  	如下即可
        private boolean setValue0(Object objResult) {
            if (RESULT_UPDATER.compareAndSet(SyncPromise.this, null, objResult)) {
                return true;
            }
            if (checkNotifyWaiters()) {
            notifyListeners();
            }
            return false;
        }
      场景:zk连接不稳定回调多次调用场景。
      或者不用这个listener,自己定义回调替代SyncPromise中listener也可以的。

第一版和第二版:

代码实现借鉴 io.netty.channel.DefaultChannelPromise 。
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
Java中,可以使用多线程异步处理任务集中统一处理结果的方式有很多,其中比较常用的方式是使用线程池和Future对象。 1. 线程池:Java提供了Executor框架,可以通过创建线程池来管理多个线程。你可以使用ThreadPoolExecutor类来创建一个线程池,并将任务提交给线程池进行执行。通过使用线程池,你可以控制并发线程的数量,避免创建过多的线程导致资源浪费。当所有任务执行完成后,你可以通过线程池的回调机制来处理任务的结果。 2. Future对象:Future是Java提供的一个接口,它表示一个异步计算的结果。你可以通过ExecutorService.submit()方法提交一个任务,并返回一个Future对象。通过Future对象,你可以检查任务是否完成、任务的执行、获取任务的执行结果等。当所有任务都提交完成后,你可以遍历Future对象集合,获取每个任务的执行结果,并进行统一处理。 下面是一个示例代码,演示了如何使用线程池和Future对象来实现多线程异步处理任务集中统一处理结果: ```java import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; public class AsyncTaskProcessor { public static void main(String[] args) { // 创建线程池 ExecutorService executor = Executors.newFixedThreadPool(5); // 创建任务列表 List<Callable<Integer>> tasks = new ArrayList<>(); tasks.add(new Task(1)); tasks.add(new Task(2)); tasks.add(new Task(3)); try { // 提交任务获取Future对象列表 List<Future<Integer>> futures = executor.invokeAll(tasks); // 处理任务结果 for (Future<Integer> future : futures) { if (future.isDone()) { int result = future.get(); System.out.println("Task result: " + result); // 统一处理任务结果 // ... } } } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } // 关闭线程池 executor.shutdown(); } static class Task implements Callable<Integer> { private int taskId; public Task(int taskId) { this.taskId = taskId; } @Override public Integer call() throws Exception { // 执行任务逻辑 Thread.sleep(1000); return taskId * 10; } } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hvang1988

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值