本文共 3270 字,大约阅读时间需要 10 分钟。
相信你已经了解过多线程的概念,不妨咱们来回顾下,做个暖场如何
相关概念
线程、进程
依赖包含关系、相似(状态)、区别(内存共享、资源共享、成本)
进程是操作系统分配资源的基础单位,而线程是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
本文出自 “” 博客,请务必保留此出处
转载地址:http://xxano.baihongyu.com/