一、基础
1.1 Callable接口
一般线程的创建有三种方式,直接继承Thread、实现Runnable接口、实现Callable接口。其中最差当属直接继承Thread,调用new Thread()创建的线程缺乏管理,可以随意创建、相互竞争。而后两种可以使用Executor框架的线程池来管理线程,执行任务,可以重用存在的线程,减少对象创建、消亡的开销,提供定时执行、定期执行、单线程、并发数控制等功能。
1.2 Executor框架
Executor框架的主要成员:
ThreadPoolExecutor
ScheduledThreadPoolExecutor
Future接口
Runnable接口
Callable接口
Executors
Java通过Executors提供几种线程池,以下为部分方法:
1.public static ExecutorService newFixedThreadPool(int nThreads) 创建固定数目线程的线程池。
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
Runnable syncRunnable = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
};
executorService.execute(syncRunnable);
}
总共只会创建5个线程,当五个线程都处于活动状态时,再次提交的任务都会加入等待队列,直到某活跃线程运行结束
2.public static ExecutorService newCachedThreadPool() 创建一个可缓存的线程池,调用execute将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
Runnable syncRunnable = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
};
executorService.execute(syncRunnable);
}
3.public static ExecutorService newSingleThreadExecutor() 创建一个单线程化的Executor。
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
Runnable syncRunnable = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
};
executorService.execute(syncRunnable);
}
只会创建一个线程,当上一个执行完之后才会执行第二个。唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
1.3 Future
Future就是对于具体的Runnable或者Callable任务的执行结果,进行取消、查询是否完成、获取结果
源码如下:
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
- cancel方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务 ;
- isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true;
- isDone方法表示任务是否已经完成,若任务完成,则返回true;
- get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;
- get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。
1.4 FutureTask
FutureTask类实现了RunnableFuture接口,而RunnableFuture继承了Runnable接口和Future接口,所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。
1.5 Callable+Future案例
public class Test {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
Task task = new Task();
Future<Integer> result = executor.submit(task);
executor.shutdown();
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("主线程:"+Thread.currentThread().getName() + " 正在执行任务!");
try {
System.out.println("task运行结果"+result.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("所有任务执行完毕");
}
}
class Task implements Callable<Integer>{
@Override
public Integer call() throws Exception {
System.out.println("子线程:" + Thread.currentThread().getName()+" 正在工作!");
Thread.sleep(3000);
int sum = 0;
for(int i=0;i<100;i++)
sum += i;
return sum;
}
}
1.6 Callable+FutureTask案例
public class Test {
public static void main(String[] args) {
//第一种方式
ExecutorService executor = Executors.newCachedThreadPool();
Task task = new Task();
FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
executor.submit(futureTask);
executor.shutdown();
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("主线程:"+Thread.currentThread().getName() + " 正在执行任务!");
try {
System.out.println("task运行结果"+futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("所有任务执行完毕");
}
}
class Task implements Callable<Integer>{
@Override
public Integer call() throws Exception {
System.out.println("子线程:" + Thread.currentThread().getName()+" 正在工作!");
Thread.sleep(3000);
int sum = 0;
for(int i=0;i<100;i++)
sum += i;
return sum;
}
}
二、分段List集合处理
public void dealListWithMutiThread(){
List<Object> list = new ArrayList<Object>(10000);
list.add("mark");
list.add("mario");
list.add("mk");
list.add("marks");
list.add("marios");
list.add("mks");
// 每n条数据开启一条线程
int threadSize = 6;
// 总数据条数
int dataSize = list.size();
// 线程数
int threadNum = dataSize / threadSize + 1;
// 定义标记 dataSize / threadSize整除时(threadNum多了一次)
boolean special = dataSize % threadSize == 0;
ExecutorService ex = Executors.newFixedThreadPool(threadNum);
List<Future<List<Object>>> futures = new ArrayList<>(threadNum);
//分配
for (int i = 0; i < threadNum; i++) {
if (i == threadNum - 1) {
if (special) {
break;
}
futures.add(ex.submit(new Task(list,threadSize * i,dataSize)));
} else {
futures.add(ex.submit(new Task(list,threadSize * i,threadSize * (i + 1))));
}
}
try {
//处理
List<Object> result = new ArrayList<>();
for(Future<List<Object>> future : futures){
//如果任务没有完成则忙等待
while (!future.isDone());
System.out.println(future.get());
//合并操作
result.addAll(future.get());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭线程池,不再接收新的任务
ex.shutdown();
}
}
private class Task implements Callable<List<Object>> {
private List<Object> list;
private int start;
private int end;
public Task(List<Object> list,int start,int end){
this.list = list;
this.start = start;
this.end = end;
}
@Override
public List<Object> call() throws Exception {
Object obj = null;
List<Object> retList = new ArrayList<Object>();
for(int i=start;i<end;i++){
obj = list.get(i);
//处理逻辑
retList.add(obj);
System.out.println("当前线程:"+ Thread.currentThread().getName());
}
//返回处理结果
return retList;
}
}