【技术交流】让我们来谈一谈多线程和并发任务
相信你已经了解过多线程的概念,不妨咱们来回顾下,做个暖场如何
相关概念
线程、进程
依赖包含关系、相似(状态)、区别(内存共享、资源共享、成本)
进程是操作系统分配资源的基础单位,而线程是CPU执行的基础单位。
线程与线程间是并列且独立的。
线程空间、ThreadLocal、线程上下文
线程运行时所占用的内存、锁、cpu等资源的一个虚拟视图
线程的一个局部变量,可以理解为与当前线程绑定的一个map
线程空间的一个实时状态
线程状态
创建、运行、阻塞、销毁
线程与锁
加锁是为了同步调度
锁的类型:共享锁、互斥锁;只读锁、可写锁
死锁
争夺资源
调度失当
线程并发模型
阻塞队列
当队列不满足操作条件时,操作线程将进入阻塞状态
- get()时,如果队列为空,则阻塞线程,直到成功执行了add()
- add()时,如果队列已满,则阻塞线程,直到成功执行了get()
最常用的一种并发调度器
eg :生产者-消费者。库房满时,生产者阻塞,直到消费者取走了库存;库房空时,消费者阻塞,直到生产者增加了库存。
闭锁
闭锁线程转换到“开门”状态之前,任何尝试“进门”的线程都会被阻塞
eg:登机。在允许登机之前,所有乘客都要等待。
关卡
所有线程都执行到“关卡”点之前,任何尝试“过关”的线程都会被阻塞
eg:大巴车。在所有人都到齐之前,大巴车不会开动。已上车的人都要等待。
线程实现
java多线程实现,有两种方法。继承Thread,实现接口Runable。大多数时候我们采用后者。原因很简单:单继承,多实现,况且java的设计原则有一条是“面向接口编程”。
测试类
public class TestMain {
@Test
public void testThread(){
//
Thread th1 = new TestNoSynThread();
Thread th2 = new TestNoSynThread();
th1.start();
th2.start();
}
@Test
public void testRunable(){
//
TestNoSynRunable r = new TestNoSynRunable();
Thread th1 = new Thread(r,"thread-a");
Thread th2 = newT hread(r,"thread-b");
th1.start();
th2.start();
}
}
注:start方法只是启动线程,使线程处于可运行状态,并没有运行。一旦得到cpu,就开始执行重写的run方法。run执行完毕,线程结束。
下面再来介绍并发实现的另一种方式,实际上是Runable方式上的封装。在JDK1.5出现之后,Sun发布的多线程并发处理的工具包
java.util.concurrent
-
Executor 并发任务执行器的顶级抽象,只针对Runnable
-
ExecutorService 对Executor进行扩展,支持Callable和Future
-
Callable 对Runnable进行扩展,提供了返回值。
-
Future 阻塞线程,直到Callable返回了值
-
FutureTask 实现了Callable和Future 可以简单理解为同时是生产者和消费者的类
-
其它 闭锁、关卡等实现
并发任务使用
- 声明一个ExecutorService
- 向ExecutorService 提交一个或多个Callable,并获取Future
- 从Future中获取Callable的返回结果
项目应用
实际上是一个“大巴车”模型
测试类
public class TestExecutorService {
private int SIZE = 10;
/**
* 计算1+2+...+100.
*
* @author wuyichen-ghq
* @since 2013-12-31
*/
@Test
public void main() {
ExecutorService exeService = Executors.newCachedThreadPool();
// 任务列表,分成1+10、11+20、。。。、91+100
List<FutureTask<Integer>> taskList = new ArrayList<FutureTask<Integer>>(SIZE);
for(inti = 0; i < SIZE; i++) {
TestFutureTask task = new TestFutureTask(i * 10+ 1, (i + 1) * 10);
taskList.add(new FutureTask<Integer>(task));
}
// 逐个提交任务(这里可以将任务创建和提交放在一个for里)
for(FutureTask<Integer> task : taskList) {
exeService.submit(task);
}
// 逐个获取任务结果
FutureTask<Integer> task = null;
// 任务序列号
int taskIndex = 0;
try{
while(taskIndex < taskList.size()) {
task = taskList.get(taskIndex);
asserttask != null;
intresult = task.get();
System.out.println(result);
taskIndex++;
}
} catch(InterruptedException e) {
e.printStackTrace();
} catch(ExecutionException e) {
e.printStackTrace();
}
}
}
task类
public class TestFutureTask implements Callable<Integer>{
private int begin;
private int end;
/**
* TODO:(构造方法描述)
*
* @author wuyichen-ghq
* @since 2013-12-31
* @param i
*/
public TestFutureTask(int begin,int end) {
this.begin = begin;
this.end = end;
}
/**
* TODO:(方法描述)
*
* @author wuyichen-ghq
* @since 2013-12-31
* @throws 无
* @see java.util.concurrent.Callable#call()
*
*/
@Override
public Integer call() throws Exception {
intresult = 0;
for(inti=begin;i<=end;i++){
result = i + result;
}
return result;
}
}
要注意的地方:
- 异常处理
- ExecutorService有两个方法:submit、execute
that's all!如果文章中什么错误,请与我联系,也欢迎您跟我邮件交流哦!
本文出自 “ ATIP團戰術策劃部” 博客,请务必保留此出处 http://atip3.blog.51cto.com/6312771/1347150