高并发之线程池

高并发之线程池

线程的开启和回收是要消耗系统性能的,对于大量使用线程的场景,使用线程池来进行管理,实现单个线程的复用,提高并发效率。

Callable
对Runnable进行了扩展,相对于Runnable接口,Callable的调用是可以有返回值的。

Future
Future接口是一个泛型的接口,该接口中定义有些一些方法,这些方法分别是:

  1. boolean cancel(boolean mayInterruptIfRunning)
    尝试去取消正在执行的任务。
  2. V get()
    这个方法是阻塞执行的,由于Future是带有返回结果的,所以,该方法一直阻塞,知道返回执行结果。
  3. V get(long timeout, TimeUnit unit)
    同上,可以设置超时时间。
  4. boolean isCancelled()
    如果在正常完成直接被取消则返回真。
  5. boolean isDone()
    如果任务完成,返回真。
    使用Future接口的一个例子

FutureTask task = new FutureTask<>(Runnable接口);
new Thread(task).start();
这里面的参数task,就可以是实现Futrue接口的对象。
这是重写FutureTask方法

/**
Created by luzhuhong on 2018/9/1.
*/

public class LFutureTask<T> implements Runnable,Future<T> {
FutureTask<T> futureTask=null;
Callable<T> callable;//业务逻辑
T result=null; //执行结果
String state="NEW";
public LFutureTask( Callable<T> callable){
    this.callable=callable;
}
@Override
public void run() {
    try{
        result=callable.call();
    }catch (Exception w){
        w.printStackTrace();
    }finally {
        state="END";
    }
    synchronized (this){
        System.out.print(Thread.currentThread().getName()+"执行完成 通知主线程");
        this.notifyAll();
    }
}

@Override
public boolean cancel(boolean mayInterruptIfRunning) {
    return false;
}

@Override
public boolean isCancelled() {
    return false;
}

@Override
public boolean isDone() {
    return false;
}
@Override
public T get() throws InterruptedException, ExecutionException {
    if("END".equals(state)){
        return result;
    }
   Thread currentThread= Thread.currentThread();
  System.out.print(currentThread.getName()+"currentThread.getName()");
   //没有执行完 阻塞线程(main)等待结果进行等待
  synchronized (this){
      this.wait();}
    return null;
}
@Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
    return null;
}}

Executor
Executor是一个接口,这个接口里面有一个名为execute的抽象函数,该函数的函数原型是是这样的:
public void execute(Runnable command)
重写该方法就可以实现应用Executor接口的功能了。

Excutor的继承树是这样的:
ExcutorService接口继承了Excutor接口,此外,该接口还重新定义了一些其他的方法,比较典型的是submit()方法,该方法能够重载多种参数,其函数原型是:
Future submit(Callable task)
Future<?> submit(Runnable task)
Future submit(Runnable task, T result)
也就是说,该接口定义的submit()方法是有返回值的,这个返回值的类型是一个Futrue类型的对象。
我们不去具体地实现该接口来实现线程池,而是使用Executors工厂类来给我们返回不同的实现了该接口的线程池实体,而我们只需要去用submit()或者excutor()方法来提交事务就可以了,在我们用工厂类进行实例化的时候,有些参数是可以传递的,但是大多数中间过程,已经由这个工厂类来完成了。
ExcutorService接口的一些常用的方法:
1.execute(Runnable)
接收一个Runnable实例,并且异步地执行
2. submit(Runnable)
submit(Runnable)和execute(Runnable)区别是前者可以返回一个Future对象,通过返回的Future对象,我们可以检查提交的任务是否执行完毕等。
3. submit(Callable)
submit(Callable)和submit(Runnable)类似,也会返回一个Future对象,但是除此之外,submit(Callable)接收的是一个Callable的实现,Callable接口中的call()方法有一个返回值,可以返回任务的执行结果,而Runnable接口中的run()方法是void修饰的,没有返回值。
  也就是说,以上的两个方法,就是用来提交给实现ExcutorService接口的具体线程池中的执行事务,通过以上两种方法,可以让线程池来执行我们需要执行的任务。
4. invokeAny(…)
接收的是一个Callable的集合,执行这个方法不会返回Future,但是会返回所有Callable任务中其中一个任务的执行结果。这个方法也无法保证返回的是哪个任务的执行结果,反正是其中的某一个。
5. invokeAll(…)
invokeAll(…)与 invokeAny(…)类似也是接收一个Callable集合,但是前者执行之后会返回一个Future的List,其中对应着每个Callable任务执行后的Future对象。
6. shutdown()
对当前线程池中已经执行的线程下达关闭命令,同时拒绝在线程池中添加新的任务,如果使用submit()添加新的任务,会产生RejectedExecutionException的异常。
7. isShutdown()
如果这个excutor()已经被下达关闭指令,则返回真,但是具体是否真的被关闭了,需要用isTerminated()方法来判断。
8. isTerminated()
如果所有任务已经完成后续的关闭工作则返回真。
Executors:
前面已经说过了,Executors类是一个静态工厂类,可以返回的类型有:

  • ExecutorService
  • ScheduledExecutorService
  • ThreadFactory
  • Callable
    通过该类的工厂方法可以返回具体功能的线程池对象,这些对象都是实现了ExcutorService接口的,我们想要提交事务,只需要调用该接口的submit()或excutor()方法就可以了,使用十分便利。其主要的工厂方法有:
    static ThreadFactory defaultThreadFactory()
    static ExecutorService newCachedThreadPool()
    static ExecutorService newCachedThreadPool(ThreadFactory threadFactory)
    static ExecutorService newFixedThreadPool(int nThreads)
    static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
    static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
    static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)
    static ExecutorService newSingleThreadExecutor()
    static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory)
    static ScheduledExecutorService newSingleThreadScheduledExecutor()
    static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory)
    static ThreadFactory privilegedThreadFactory()
    static ExecutorService unconfigurableExecutorService(ExecutorService executor)
    static ScheduledExecutorService unconfigurableScheduledExecutorService
    比较常用的线程池的5种创建方式:
  1. SingleThread Executor
    只有一个线程的线程池,因此所有提交的任务是顺序执行,代码:

Executors.newSingleThreadExecutor()

Cached Thread Pool
线程池里有很多线程需要同时执行,旧的可用线程将被新的任务触发重新执行,如果线程超过60秒内没执行,那么将被终止并从池中删除,代码:
Executors.newCachedThreadPool()
FixedThreadPool
拥有固定线程数的线程池,如果没有任务执行,那么线程会一直等待,代码:
Executors.newFixedThreadPool(4)
在构造函数中的参数4是线程池的大小,一般设置与cpu的数量保持一致,获取cpu的数量:

int cpuNums = Runtime.getRuntime().availableProcessors();
ScheduledThreadPool
用来调度即将执行的任务的线程池,代码:
Executors.newScheduledThreadPool()
Single Thread Scheduled Pool
只有一个线程,常用来调度执行将来的任务,代码:
Executors.newSingleThreadScheduledExecutor()

下面利用线程池并发调用模拟接口示例

 public class futureTaskAndCallback {
final static ExecutorService executor= Executors.newFixedThreadPool(2);
public static  void main(String[] args) throws Exception{
    RpcService rpcService=new RpcService();
    HttpclientService httpclientService=new HttpclientService();
    Future<Integer> a=null;
    Future<Integer> b=null;
    a=executor.submit(()->rpcService.getPrcResult());
    b=executor.submit(()->httpclientService.getHttpesult());
    long startTime=System.currentTimeMillis();   //获取开始时间
    Integer c=a.get(30000, TimeUnit.MILLISECONDS);
    long endTime=System.currentTimeMillis(); //获取结束时间
    System.out.println("a程序运行时间: "+(endTime-startTime)+"ms");
    long bstartTime=System.currentTimeMillis();   //获取开始时间
    Integer d=b.get(30000, TimeUnit.MILLISECONDS);
    long bendTime=System.currentTimeMillis(); //获取结束时间
    System.out.println("b程序运行时间: "+(bendTime-bstartTime)+"ms");
    System.out.println("一共程序运行时间: "+(bendTime-startTime)+"ms");
    CompletableFuture qw=new CompletableFuture();


}
static class RpcService{
    Integer getPrcResult() throws Exception{
        Thread.sleep(10000);
        return 1;
    };
}
static class HttpclientService{
    Integer getHttpesult() throws Exception{
        Thread.sleep(20000);
        return 0;
    }
}}

调用记录
在这里插入图片描述

ForkJoinPool
Jdk7新增了并发框架fork/join框架,在这种框架下,ForkJoinTask代表一个需要执行的任务,真正执行这些任务的线程是放在一个线程池(ForkJoinPool)里面。ForkJoinPool是一个可以执行ForkJoinTask的ExcuteService,与ExcuteService不同的是它采用了work-stealing模式:
jdk1.8中出来的completeable就是利用ForkJoin并发编排技术 前面springcloud里面有介绍

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值