JAVA异步实现的四种方式

一、使用Thread类

可以使用Thread类来创建一个新的线程,并在其run()方法中执行操作。例如:

public class MiniProgramController extends Thread{
    @Override
    public void run() {
        System.out.println("1111");
    }
    public static void main(String[] args) {
        MiniProgramController min=new MiniProgramController();
        min.start();
        System.out.println("helloworl");
    }
}

二、使用Runnable接口

可以通过实现Runnable接口并在其中实现耗时操作,并通过Thread类来启动新线程。例如:

public class MiniProgramController implements Runnable{
    @Override
    public void run() {
        System.out.println("1111");
    }
    public static void main(String[] args) {
        MiniProgramController min=new MiniProgramController();
        min.start();
        System.out.println("helloworl");
    }
}

三、使用Callable 接口

前面有两种创建线程的方法,一种是通过创建 Thread 类,另一种是通过使用 Runnable 创建线程。但是,Runnable 缺少的一项功能是,当线程终止时(即 run()完成时),我们无法使线程返回结果。为了支持此功能,Java 中提供了 Callable 接口。

Callable 接口的特点如下(重点)

• 为了实现 Runnable,需要实现不返回任何内容的 run()方法,而对于Callable,需要实现在完成时返回结果的 call()方法。

• call()方法可以引发异常,而 run()则不能。

• 为实现 Callable 而必须重写 call 方法

• 不能直接替换 runnable,因为 Thread 类的构造方法根本没有 Callable

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

class MyThread implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        return 200;
    }
}

public class CallableDemo {
    public static void main(String[] args) {
        //方式一
        FutureTask<Integer> futureTask = new FutureTask<>(new MyThread());
        new Thread(futureTask).start();
        //方式二
        FutureTask<Integer> integerFutureTask = new FutureTask<>(() -> {
            System.out.println(Thread.currentThread().getName());
            return 1024;
        });
        new Thread(integerFutureTask,"lucy").start();
    }
}

由于FutureTask实现的是RunnableFuture接口,而RunnableFuture实现了Runnable和Future。
因此

1. FutureTask可作为Runnable的实现传入Thread构造方法中

2. 需要实现callable中的call方法,这个call方法就是我们需要写的逻辑了,需要让这个线程做什么以及需要返回什么结果

四、使用Executor和ThreadPool

可以使用Executor和ThreadPool来创建和管理线程池,从而执行异步操作。例如:

1、Executor

public class MiniProgramController implements Runnable{
    
    private static ExecutorService executorService = Executors.newCachedThreadPool();

    public static void main(String[] args) {
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("1111");
            }
        });

        System.out.println("helloworld");
    }
}

2、ThreadPool

1、七个参数

• corePoolSize 线程池的核心线程数

• maximumPoolSize 能容纳的最大线程数

• keepAliveTime 空闲线程存活时间

• unit 存活的时间单位

• workQueue 存放提交但未执行任务的队列

• threadFactory 创建线程的工厂类

• handler 等待队列满后的拒绝策略

线程池中,有三个重要的参数,决定影响了拒绝策略:corePoolSize - 核心线程数,也即最小的线程数。workQueue - 阻塞队列 。 maximumPoolSize - 最大线程数

当提交任务数大于 corePoolSize 的时候,会优先将任务放到 workQueue 阻塞队列中。当阻塞队列饱和后,会扩充线程池中线程数,直到达到maximumPoolSize 最大线程数配置。此时,再多余的任务,则会触发线程池的拒绝策略了。

总结起来,也就是一句话,当提交的任务数大于(workQueue.size() + maximumPoolSize ),就会触发线程池的拒绝策略

2、拒绝策略(重点)

CallerRunsPolicy: 当触发拒绝策略,只要线程池没有关闭的话,则使用调用线程直接运行任务。一般并发比较小,性能要求不高,不允许失败。但是,由于调用者自己运行任务,如果任务提交速度过快,可能导致程序阻塞,性能效率上必然的损失较大

AbortPolicy: 丢弃任务,并抛出拒绝执行RejectedExecutionException 异常 信息。线程池默认的拒绝策略。必须处理好抛出的异常,否则会打断当前的执行流程,影响后续的任务执行。

DiscardPolicy: 直接丢弃,其他啥都没有

DiscardOldestPolicy: 当触发拒绝策略,只要线程池没有关闭的话,丢弃阻塞队列 workQueue 中最老的一个任务,并将新任务加入

3、代码

//自定义线程池的创建
public class ThreadPoolDemo3 {
    public static void main(String[] args) {
        Integer processNum = Runtime.getRuntime().availableProcessors();
        int corePoolSize = (int) (processNum / (1 - 0.2));
        int maxPoolSize = (int) (processNum / (1 - 0.5));
        ExecutorService threadPool = new ThreadPoolExecutor(
            corePoolSize,
            maxPoolSize,
            2L,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(3),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.CallerRunsPolicy()
        );
        
    
        for (int i = 1; i <=10 ; i++) {
            //执行
            threadPool.execute(()->{
                System.out.println(Thread.currentThread().getName()+"办理业务");
        });
      }        
    }
}

备:如果在日常工作中建议使用ThreadPoolExecutor手动创建线程池,并指定合理的线程数量和队列容量,以及适当的拒绝策略,如果直接去使用Executor去线程池有可能会出现OOM的现象。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Java 中使用 gRPC 传输文件的异步方式,需要借助 gRPC 的流式传输能力。 以下是一个基本的 gRPC 文件传输的异步实现示例: 首先,在.proto文件中定义文件传输的方法: ``` service FileTransferService { rpc uploadFile(stream FileChunk) returns (UploadStatus); } message FileChunk { bytes data = 1; } message UploadStatus { bool success = 1; } ``` 接下来,在Java实现异步上传文件的客户端: ``` // 定义异步上传文件的回调接口 public interface FileUploadCallback { void onSuccess(); void onError(Throwable t); } // 客户端异步上传文件 public class FileUploadClient { private final FileTransferServiceStub stub; public FileUploadClient(FileTransferServiceStub stub) { this.stub = stub; } public void uploadFile(File file, FileUploadCallback callback) { try { FileInputStream inputStream = new FileInputStream(file); StreamObserver<FileChunk> requestObserver = stub.uploadFile(new StreamObserver<UploadStatus>() { @Override public void onNext(UploadStatus status) { if (status.getSuccess()) { callback.onSuccess(); } else { callback.onError(new RuntimeException("Upload failed")); } } @Override public void onError(Throwable t) { callback.onError(t); } @Override public void onCompleted() { // Do nothing } }); byte[] buffer = new byte[4096]; int bytesRead = -1; while ((bytesRead = inputStream.read(buffer)) != -1) { FileChunk chunk = FileChunk.newBuilder().setData(ByteString.copyFrom(buffer, 0, bytesRead)).build(); requestObserver.onNext(chunk); } requestObserver.onCompleted(); } catch (IOException e) { callback.onError(e); } } } ``` 最后,在Java实现异步接收文件的服务端: ``` // 服务端异步接收文件 public class FileTransferServiceImpl extends FileTransferServiceGrpc.FileTransferServiceImplBase { @Override public StreamObserver<FileChunk> uploadFile(StreamObserver<UploadStatus> responseObserver) { return new StreamObserver<FileChunk>() { private FileOutputStream outputStream; @Override public void onNext(FileChunk chunk) { try { if (outputStream == null) { File tempFile = File.createTempFile("temp", "upload"); outputStream = new FileOutputStream(tempFile); } outputStream.write(chunk.getData().toByteArray()); } catch (IOException e) { onError(e); } } @Override public void onError(Throwable t) { if (outputStream != null) { try { outputStream.close(); } catch (IOException e) { // Ignore } } responseObserver.onError(t); } @Override public void onCompleted() { try { outputStream.close(); responseObserver.onNext(UploadStatus.newBuilder().setSuccess(true).build()); responseObserver.onCompleted(); } catch (IOException e) { onError(e); } } }; } } ``` 以上就是一个基本的 gRPC 文件传输的异步实现示例。需要注意的是,在实际应用中,可能需要对上传和下载的文件进行分片,以便更好地管理和控制传输过程。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小小小王w

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

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

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

打赏作者

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

抵扣说明:

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

余额充值