夜光:Java成神之路(十一)擅长的语言

夜光序言:

 

没有谁的生活会一直完美,但无论什么时候,都要看向前方,满怀希望就会所向披靡。

 

 

 

 

 

 

 
 
正文:
 
                                              以道御术 / 以术识道



单任务连接池

 
 
我们将上面的代码
//创建一个可重用固定线程数的线程池
ExecutorService pool = Executors.newFixedThreadPool(2);
 //改为:
 //创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。
ExecutorService pool = Executors.newSingleThreadExecutor();

运行结果看出,单任务线程池在执行 execute 方法来执行 Thread 类中的 run 方法。

不管 execute 执行几次,线程池始终都会使用单个线程来处理。

 

 
补充:在 java 的多线程中,一但线程关闭,就会成为死线程。关闭后死线程就没有办法在启动了。再次启动就会出现

 

异常信息:Exception in thread "main" java.lang.IllegalThreadStateException。那么如何解决这个问题呢?
 
我们这里就可以使用 Executors.newSingleThreadExecutor()来再次启动一个线程。

 


 

延迟连接池

package com.hy.多线程高并发;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * Java 线程:线程池-
 *
 * @author
 */
public class Test9 {

    public static void main(String[] args) {
//创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);
        //创建实现了 Runnable 接口对象,Thread 对象当然也实现了 Runnable 接口
        Thread t1 = new MyThread1();
        Thread t2 = new MyThread1();
        Thread t3 = new MyThread1();
        Thread t4 = new MyThread1();
        Thread t5 = new MyThread1();
        //将线程放入池中进行执行
        pool.execute(t1);
        pool.execute(t2);
        pool.execute(t3);
        //使用定时执行风格的方法
        pool.schedule(t4, 10, TimeUnit.MILLISECONDS); //t4 和 t5 在 10 秒后执行
        pool.schedule(t5, 10, TimeUnit.MILLISECONDS);
        //关闭线程池
        pool.shutdown();
    }
}

class MyThread1 extends Thread {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "正在执行。。。");
    }
}


ExecutorService 执行器服务

 
 
java.util.concurrent.ExecutorService 接口表示一个异步执行机制,使我们能够在后台执行任务。
 
因此一个 ExecutorService 很类似于一个线程池。实际上,存在于 java.util.concurrent 包里的 ExecutorService 实现就是一个线程池实现。
 
 
 

ExecutorService 例子


以下是一个简单的 ExecutorService 例子:

 

//线程工厂类创建出线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
//执行一个线程任务
executorService.execute(new Runnable() {
public void run() {
System.out.println("Asynchronous task");
}
});
//线程池关闭
executorService.shutdown();

上面代码首先使用 newFixedThreadPool() 工厂方法创建一个 ExecutorService。

 

这里创建了一个十个线程执行任务的线程池。

然后,将一个 Runnable 接口的匿名实现类传递给 execute() 方法。

 

这将导致 ExecutorService 中的某个线程执行该 Runnable。

 
 
这里可以看成一个 任务分派 ,示例代码中的任务分派我们可以理解为:
 
一个线程将一个任务委派给一个 ExecutorService 去异步执行。
 
一旦该线程将任务委派给 ExecutorService,该线程将继续它自己的执行,独立于该任务的执行。
 

 

如下图:

 

ExecutorService 实现:

 
既然 ExecutorService 是个接口,如果你想用它的话就得去使用它的实现类之一。
 
java.util.concurrent 包提供了 ExecutorService 接口的以下实现类:
  ThreadPoolExecutor
  ScheduledThreadPoolExecutor
 

 

ExecutorService 创建:

 
ExecutorService 的创建依赖于你使用的具体实现。
 
但是你也可以使用 Executors 工厂类来创建 ExecutorService 实例。

 

 

代码示例:

ExecutorService executorService1 = Executors.newSingleThreadExecutor(); //之前 Executors 已介绍
ExecutorService executorService2 = Executors.newFixedThreadPool(10);
ExecutorService executorService3 = Executors.newScheduledThreadPool(10);

ExecutorService 使用:

 
 
有几种不同的方式来将任务委托给 ExecutorService 去执行:
 

    execute(Runnable)

    submit(Runnable)

    submit(Callable)

    invokeAny(…)

    invokeAll(…)

 

 
接下来我们挨个看一下这些方法。
 
execute(Runnable)
 
execute(Runnable) 方法要求一个 java.lang.Runnable 对象,然后对它进行异步执行。以下是使用ExecutorService 执行一个 Runnable 的示例:
//从 Executors 中获得 ExecutorService 
ExecutorService executorService = Executors.newSingleThreadExecutor();
//执行 ExecutorService 中的方法
executorService.execute(new Runnable() {
public void run() {
System.out.println("Asynchronous task");
}
});
//线程池关闭
executorService.shutdown();

特点:没有办法得知被执行的 Runnable 的执行结果。如果有需要的话你得使用一个 Callable(以下将做介绍)。

 

submit(Runnable)

 

submit(Runnable) 方法也要求一个 Runnable 实现类,但它返回一个 Future 对象。这个 Future 对象可以用来检查 Runnable 是否已经执行完毕。

 

以下是 ExecutorService submit() 示例:

//从 Executors 中获得 ExecutorService 
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future future = executorService.submit(new Runnable() {
public void run() {
System.out.println("Asynchronous task");
}
});
future.get(); //获得执行完 run 方法后的返回值,这里使用的 Runnable,所以这里没有返回值,返回的是 null。
executorService.shutdown();
submit(Runnable)
 
 
submit(Callable) 方法类似于 submit(Runnable) 方法,除了它所要求的参数类型之外。Callable 实例除了它的 call() 方法能够返回一个结果之外和一个 Runnable 很相像。
 
Runnable.run() 不能够返回一个结果。
 
Callable 的结果可以通过 submit(Callable) 方法返回的 Future 对象进行获取。
 
 

以下是一个 ExecutorService Callable 示例:

//从 Executors 中获得 ExecutorService 
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future future = executorService.submit(new Callable(){
public Object call() throws Exception {
System.out.println("Asynchronous Callable");
return "Callable Result";
}
});
System.out.println("future.get() = " + future.get());
executorService.shutdown();
输出:
Asynchronous Callable
future.get() = Callable Result
invokeAny()
 
invokeAny() 方法要求一系列的 Callable 或者其子接口的实例对象。调用这个方法并不会返回一个 Future,
 
但它返回其中一个 Callable 对象的结果。无法保证返回的是哪个 Callable 的结果 – 只能表明其中一个已执行结束。
 
 
如果其中一个任务执行结束(或者抛了一个异常),其他 Callable 将被取消。
 

以下是示例代码:

ExecutorService executorService = Executors.newSingleThreadExecutor();
Set<Callable<String>> callables = new HashSet<Callable<String>>();
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 1";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 2";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 3";
}
});
String result = executorService.invokeAny(callables);
System.out.println("result = " + result);
executorService.shutdown();
上述代码将会打印出给定 Callable 集合中的一个的执行结果。我自己试着执行了它几次,结果始终在变。
 
有时是 “Task 1″,有时是 “Task 2″ 等等。
 

 

invokeAll()

 
invokeAll() 方法将调用你在集合中传给 ExecutorService 的所有 Callable 对象。
 
invokeAll() 返回一系列的 Future 对象,通过它们你可以获取每个 Callable 的执行结果。
 
记住,一个任务可能会由于一个异常而结束,因此它可能没有 "成功"。无法通过一个 Future 对象来告知我们是两种结束中的哪一种。
 

 

以下是一个代码示例:

ExecutorService executorService = Executors.newSingleThreadExecutor();
Set<Callable<String>> callables = new HashSet<Callable<String>>();
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 1";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 2";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 3";
}
});
List<Future<String>> futures = executorService.invokeAll(callables);
for(Future<String> future : futures){
System.out.println("future.get = " + future.get());
}
executorService.shutdown();

Executors 关闭:

 

使用 shutdown 和 shutdownNow 可以关闭线程池

两者的区别:

 
 
shutdown 只是将空闲的线程 interrupt() 了,shutdown()之前提交的任务可以继续执行直到结束。
 
shutdownNow 是 interrupt 所有线程, 因此大部分线程将立刻被中断。
 
 
之所以是大部分,而不是全部 , 是因为 interrupt()方法能力有限。

 

 

ThreadPoolExecutor 线程池执行者

 
java.util.concurrent.ThreadPoolExecutor 是 ExecutorService 接口的一个实现。ThreadPoolExecutor 使用 其内部池中的线程执行给定任务(Callable 或者 Runnable)。
 
ThreadPoolExecutor 包含的线程池能够包含不同数量的线程。池中线程的数量由以下变量决定:
   corePoolSize
   maximumPoolSize
 
当一个任务委托给线程池时,如果池中线程数量低于 corePoolSize,一个新的线程将被创建,即使池中可能尚有空 闲 线 程 。
 
如 果 内 部 任 务 队 列 已 满 , 而 且 有 至 少 corePoolSize 正 在 运 行 , 但 是 运 行 线 程 的 数 量 低 于 maximumPoolSize,一个新的线程将被创建去执行该任务。

 

ThreadPoolExecutor 图解:

 

创建 ThreadPoolExecutor:

int corePoolSize = 5;
int maxPoolSize = 10;
long keepAliveTime = 5000;
ExecutorService threadPoolExecutor = new ThreadPoolExecutor(
corePoolSize,
maxPoolSize,
keepAliveTime,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()
);




构造方法参数列表解释:
corePoolSize - 池中所保存的线程数,包括空闲线程。
maximumPoolSize - 池中允许的最大线程数。
keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
unit - keepAliveTime 参数的时间单位。
workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。

ScheduledPoolExecutor 定时线程池执行者

 
java.util.concurrent.ScheduledExecutorService 是一个 ExecutorService,它能够将任务延后执行
 
 
或者间隔固定时间多次执行。 任务由一个工作者线程异步执行,而不是由提交任务给 ScheduledExecutorService 的那个线
程执行。
 
 

ScheduledPoolExecutor 例子:

ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
ScheduledFuture scheduledFuture = scheduledExecutorService.schedule(new Callable() {
public Object call() throws Exception {
System.out.println("Executed!");
return "Called!";
}
},
5,
TimeUnit.SECONDS);//5 秒后执行
首先一个内置 5 个线程的 ScheduledExecutorService 被创建。之后一个 Callable 接口的匿名类示例被创建
 
然后传递给 schedule() 方法。后边的俩参数定义了 Callable 将在 5 秒钟之后被执行。
 

 

ScheduledExecutorService 的实现:

 

ScheduledExecutorService 是一个接口,你要用它的话就得使用 java.util.concurrent 包里对它的某个实现类。

 

ScheduledExecutorService 具有以下实现类:ScheduledThreadPoolExecutor

 

创建一个 ScheduledExecutorService:

 
如何创建一个 ScheduledExecutorService 取决于你采用的它的实现类。但是你也可以使用 Executors 工厂类
 
来创建一个 ScheduledExecutorService 实例。比如:

 

ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);

ScheduledExecutorService 的使用:

一旦你创建了一个 ScheduledExecutorService,你可以通过调用它的以下方法:

 
  schedule (Callable task, long delay, TimeUnit timeunit)
  schedule (Runnable task, long delay, TimeUnit timeunit)
  scheduleAtFixedRate (Runnable, long initialDelay, long period, TimeUnit timeunit)
  scheduleWithFixedDelay (Runnable, long initialDelay, long period, TimeUnit timeunit)
 
 
下面我们就简单看一下这些方法。
 
schedule (Callable task, long delay, TimeUnit timeunit)
 
 
ScheduledExecutorService scheduledExecutorService =
Executors.newScheduledThreadPool(5);
ScheduledFuture scheduledFuture =
scheduledExecutorService.schedule(new Callable() {
public Object call() throws Exception {
System.out.println("Executed!");
return "Called!";
}
},
5,
TimeUnit.SECONDS);
System.out.println("result = " + scheduledFuture.get());
scheduledExecutorService.shutdown();

 

 

输出结果:
Executed!
result = Called!

 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值