相信你已经了解过多线程的概念,不妨咱们来回顾下,做个暖场如何
相关概念
线程、进程
依赖包含关系、相似(状态)、区别(内存共享、资源共享、成本)
进程是操作系统分配资源的基础单位,而线程是CPU执行的基础单位。
线程与线程间是并列且独立的。
线程空间、ThreadLocal、线程上下文
线程运行时所占用的内存、锁、cpu等资源的一个虚拟视图
线程的一个局部变量,可以理解为与当前线程绑定的一个map
线程空间的一个实时状态
线程状态
创建、运行、阻塞、销毁
线程与锁
加锁是为了同步调度
锁的类型:共享锁、互斥锁;只读锁、可写锁
死锁
争夺资源
调度失当
线程并发模型
阻塞队列
当队列不满足操作条件时,操作线程将进入阻塞状态
get()时,如果队列为空,则阻塞线程,直到成功执行了add()
add()时,如果队列已满,则阻塞线程,直到成功执行了get()
最常用的一种并发调度器eg :生产者-消费者
闭锁
闭锁线程转换到“开门”状态之前,任何尝试“进门”的线程都会被阻塞
eg:登机
关卡
所有线程都执行到“关卡”点之前,任何尝试“过关”的线程都会被阻塞
eg:大巴车
线程实现
java多线程实现,有两种方法。继承Thread,实现接口Runable。大多数时候我们采用后者。原因很简单:单继承,多实现,况且java的设计原则有一条是“面向接口编程”。
测试类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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 =
new
Thread(r,
"thread-b"
);
th1.start();
th2.start();
}
}
|
注:start方法只是启动线程,使线程处于可运行状态,并没有运行。一旦得到cpu,就开始执行重写的run方法。run执行完毕,线程结束。
下面再来介绍并发实现的另一种方式,实际上是Runable方式上的封装。在JDK1.5出现之后,Sun发布的多线程并发处理的工具包
java.util.concurrent
Executor
并发任务执行器的顶级抽象,只针对RunnableExecutorService
对Executor进行扩展,支持Callable和FutureCallable
对Runnable进行扩展,提供了返回值。Future
阻塞线程,直到Callable返回了值FutureTask
实现了Callable和Future
可以简单理解为同时是生产者和消费者的类其它
闭锁、关卡等实现
并发任务使用
声明一个ExecutorService
向ExecutorService 提交一个或多个Callable,并获取Future
从Future中获取Callable的返回结果
项目应用
实际上是一个“大巴车”模型
测试类
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
31
32
33
34
35
36
37
38
39
40
41
|
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
(
int
i =
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);
assert
task !=
null
;
int
result = task.get();
System.out.println(result);
taskIndex++;
}
}
catch
(InterruptedException e) {
e.printStackTrace();
}
catch
(ExecutionException e) {
e.printStackTrace();
}
}
}
|
task类
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
31
32
33
34
|
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 {
int
result =
0
;
for
(
int
i=begin;i<=end;i++){
result = i + result;
}
return
result;
}
}
|
要注意的地方:
异常处理
ExecutorService有两个方法:submit、execute
that's all!如果文章中什么错误,请与我联系,也欢迎您跟我邮件交流哦!
邮箱:wyc_job@163.com
本文出自 “ATIP團戰術策劃部” 博客,请务必保留此出处http://atip3.blog.51cto.com/6312771/1347150