Java多线程执行框架

为什么需要执行框架呢?

使用一般的new方法来创建线程有什么问题呢?一般的new线程的方式一般要给出一个实现了Runnable接口的执行类,在其中重写run()方法,然后再在将这个执行类的对象传给线程以完成初始化,这个过程中线程的定义和执行过程其实是杂糅在一起了,而且每次new一个新的线程出来在资源上很有可能会产生不必要的消耗,因此我们通过多线程执行框架来解决这两个问题,其一可以分离线程的定义和执行过程,其二可以通过线程池来动态地管理线程以减小不必要的资源开销。

线程执行框架启动线程

将要多线程执行的任务封装为一个Runnable对象,将其传给一个执行框架Executor对象, Executor从线程池中选择线程执行工作任务。

创建多线程框架对象调用线程执行任务
我们通常通过Executors类的一些静态方法来实例化Executor或ThreadPoolExecutor对象:

比如Executor对象来执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class ThreadTest {
public static void main(String[] args) {
Executor executor = Executors.newSingleThreadExecutor();
executor.execute(new MyRunnable());
}
}

class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("running");
}
}

比如线程池的Executor对象来执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ThreadTest {
public static void main(String[] args) {
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors
.newFixedThreadPool(3);
executor.execute(new MyRunnable());
}
}

class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("running");
}
}
  • Executors. newSingleThreadExecutor():一 个线程死掉后,自动重新创建后一个新的线程,所以没有线程池的概念,不能被ThreadPoolExecutor接收;
  • Executors. newFixedThreadPool():固定数目的线程池;
  • Executors. newCachedThreadPool():动态地增加和减少线程数;

多线程框架对象调用线程执行任务取回结果

实现了Runnable接口的执行类虽然可以在run()方法里写入执行体,但是无法返回结果值,因为run()方法是void型的,而Callable接口解决了这个问题,在继承了Callable接口的执行类中重写call()方法可以设置返回值,当Executor对象使用submit()函数提交执行类的时候会由线程池里的线程来运行,运行得到的返回值可以使用Future接口来接,取得的返回值类型由V决定,Future接口表示可能会得到的返回值,但是有可能报异常,因此要抛出这些异常,然后可以取得这些返回值。

1.invokeAny():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class ThreadTest {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
List<MyCallable> callables = new ArrayList<>();
for(int i=0;i<10;i++){
MyCallable myCallable = new MyCallable(i);
callables.add(myCallable);
}
Integer res = executor.invokeAny(callables);
System.out.println(res);

}
}

class MyCallable implements Callable<Integer> {
private int num;

public MyCallable(int num) {
this.num = num;
}

@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName() + " is running");
return num * 2;
}
}

2.invokeAll():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class ThreadTest {
public static void main(String[] args) throws InterruptedException,
ExecutionException {

ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors
.newFixedThreadPool(5);
List<MyCallable> callables = new ArrayList<MyCallable>();
for (int i = 0; i < 10; i++) {
MyCallable myCallable = new MyCallable(i);
callables.add(myCallable);
}
List<Future<Integer>> res = executor.invokeAll(callables);
for (Future<Integer> future : res) {
System.out.println(future.get());
}
}
}

class MyCallable implements Callable<Integer> {
private int num;

public MyCallable(int num) {
this.num = num;
}

@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName() + " is running");
return num * 2;
}
}

多线程框架对象执行定时任务

使用Executor的schedule()函数族来调度线程池中的线程来执行callable执行类对象中的call()定时任务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class ThreadTest {
public static void main(String[] args) throws InterruptedException,
ExecutionException {

ScheduledExecutorService executorService = Executors
.newScheduledThreadPool(2);
MyCallable callable = new MyCallable(2);
executorService.schedule(callable, 10, TimeUnit.SECONDS);
executorService.shutdown();
}
}

class MyCallable implements Callable<Integer> {
private int num;

public MyCallable(int num) {
this.num = num;
}

@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName() + " is running");
return num * 2;
}
}