首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

体会Java中的多线程设计

2012-08-15 
感受Java中的多线程设计欢迎转载,转载请注明出处:http://it.zhutibo.com/action/article1231.htm并行编程

感受Java中的多线程设计
欢迎转载,转载请注明出处:http://it.zhutibo.com/action/article1231.htm并行编程的革命Java多线程线程对象设计Thread类Runnable & CallableExecutorService管理类异常处理其它:守护线程及优先级CPU协调Sleep()方法Yield()方法资源协调原子性 & volatile块状隐式锁synchronized显式锁wait & notify & notifyAllThreadLocal终止终程一个实例 并行编程的革命

我就不说最初那个单核CPU时代了,我们从多进程编程开始讲。在引入多线程概念前,多进程是并发编程的唯一解决方案;多进程在解决并发问题的同时带来了一些问题:主要有以下几点,多线程也就是正因为多进程有许多不足才被设计出来:

多进程的特点:每个进程都独立拥有数据空间(堆、栈、代码区等),这是多线程跟多进程最本质的区别,这个区别是多线程与多进程优缺点的起因

多进程缺点:

进程间数据共享困难进程调试时上下文切换开销大线程给异步设计提供了方便的设计模式

多进程优点:

进程与进程间的执行没有相互干扰(暂不考虑进程间通讯问题),进程基本上可以随时终时,所以操作系统会提供给我们任务管理器来强制终止进程,或是提供kill命令。线程这样做往往很危险,线程的终止方法也很特殊,后面我们会讲到;因为强制终止线程不能保证数据的一致性、完整性。进程能非常方便地应用于分布式环境

结论:多线程是不能完全替换多进程,但多线程带来的革命也是明显的,我程序设计中,我们要跟据实际情况,选择合理的并发方案;其实好多时候,我们往往是两者结合来用。好了,对多线程的基本概念讲到这里,我们以下要讲讲Java对多线程的支持。

Java多线程线程对象设计

如果Java不是一门面象对象语言,那么我们要学习的东西可能少得多,但使用起来并不一定方便。我们先来讲一下Java中多线程的设计。Java中一切都是对像,线程也是,线程是CPU调度的单位,它本身跟具体的程序功能无关;所以Java把程序的功能又独立提取出来,放到Runnable或Callable接口中;最后Java添加了一个管理类ExecotorSerivce,用于管理多个线程的执行。

Thread类

一个Thread类表示一个线程,其实一个线程可以抽象为一个程序指针,保存了程序当前的执行进度;当然,其实一个线程的实现相对复杂,还包括锁的实现等,这个说法仅供理解。

一个thread对象包含了一些关键信息

线程的状态:线程栈信息(每个线程都有个独立的栈)、中断标记信息(用于停止线程)、守护线程标记、名字、优先级等线程的一个协作方法:t.join(); //让调用者等待t线程的执行,并阻塞调用线程。run(); //重新调用new Runnable().run(); 语法上讲,可以在这个方法里直接添加线程功能,但不推介。start(); //启动线程Thread类方法:Thread类里有一些特殊的方法,这些方法都默认针对“当前运行”的线程,其它是一些所有线程的总体信息,以下是一些关键方法currentThread(); //获得当前线程sleep(); //让当前线程等待一段时间,些时不释放锁,仅不去抢占CPU。sleep并不直接干扰其它线程的执行。yield(); //让当前线程释放一下CPU。interrupted(); //返回当前线程的中断状态,并重置中断标记。

Runnable & Callable类

线程执行的具体功能被放在这个接口类里,如果涉及到资源协作(锁或是synchronized),我一般不直接在这两个类里处理这些,因为Runnable及Callable是两个行为类,一般不在这两个类里直接包含资源,所以一般不涉及到资源的锁问题;这样做也是为了让自己的程序更加容易阅读;然而一般退出线程的逻辑却应放在这个类里。

Callable相对于Runnable给我们带来了两个额外功能

线程执行返回执行结果 Callable<returnType>可抛出异常,表示取得返回值的过程中遇到了其它状况,而不至于让我们发现返回值莫名其妙地没了

线程返回结果其实在绝大多数情况下其它是没必要的,但这种情况也不算太少数;我想说明的是,相对于Runnable来说Callable并没有带来革命性的更改,所以喜欢优先用哪个,我们可以跟据需要来;我一般会优先用Runnable+ExecutorSerivce;因为即使突然发现需要返回值,把Runnable修改为Callable也不是一件复杂的事。

ExecutorService管理类

相对于Callable,我觉得这个类实用多了;这类有以下特点:

个数限制:以池的方式管理线程,用户不再需要自己创建线程,并能对线程的总个数加以限制;线程复用:除此之外,我们知道一般情况下我们都是一个线程对应一个Task,这样的线程是不能复用的,虽然我们说创建线程的开销远小于创建进程,但创建一个线程的开销相对于一般的编程还是要大得多的,默认Thread对象也没有给我们提供支持多个Task的方法,原因是需要满足太多的条件,这样做很危险;而ExecutorSerivce的池机制已经帮我们实现了这个功能。最后,ExecutorService提供了submit方法;这个方法有两个功能1、Runnable与Callable统一创建接口;2、跟踪线程的执行状态Future<return type>。

异常处理

异常是与线程对应的,我们知道当主线程抛出uncatched异常时,会造成jvm挂掉,并打印出栈信息。虽然这个功能也就这样,但至少我们知道自己的程序已经出状况了,需要重新维护。

子线程默认不会通知uncached异常信息,出现异常时,子线程挂掉,但我们什么也不知道。我们可以通过以下方法来外理这种异常

package test;import java.io.IOException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class MultiThreadDemo {/** * 这里我们定义一个线程安全的的ResHolder类 * add 用于添加某个资源,为了保证资源耗尽,我们给它设定一个上限Max,如果大于这个上限,那么就让clear方法重置一下. * @author Mr.He */static class ResHolder{public static final int Max = 10000; //read onlyprivate int i = 0;//把这个当成共享变量/** * 我们一般不会在这个类里处理interruptedException,因为我们在这里不能确认是否要退出线程. * 而synchronized等锁操作一般都放在这个类里 * @throws InterruptedException * @author Mr.He */public synchronized void add() throws InterruptedException{while(true){if(i<Max){i++;}else{notifyAll();wait();}}}public synchronized void clear() throws InterruptedException{while(true){if(i<Max){wait();}else{System.out.println("Clear value from 100 to 0 [Input ENTER to exit]");i = 0;notifyAll();}}}}/** * 在Runnable的接口实现类里,是处理Interrupted异常最好的地方. * @author Mr.He */static class TaskAdd implements Runnable{private ResHolder resHolder;private TaskAdd(ResHolder resHolder) {super();this.resHolder = resHolder;}@Overridepublic void run() {try {resHolder.add();} catch (InterruptedException e) {System.out.println("Exit for interrupt! "+Thread.currentThread());}}}static class TaskClear implements Runnable{private ResHolder resHolder;private TaskClear(ResHolder resHolder) {super();this.resHolder = resHolder;}@Overridepublic void run() {try {resHolder.clear();} catch (InterruptedException e) {System.out.println("Exit for interrupt! "+Thread.currentThread());}}}public static void main(String[] args) throws IOException {ResHolder resHolder = new ResHolder();ExecutorService exec = Executors.newCachedThreadPool();exec.submit( new TaskAdd(resHolder) );exec.submit( new TaskAdd(resHolder) );exec.submit( new TaskClear(resHolder) );//退出~if(System.in.read()!=-1){exec.shutdownNow();}}}


热点排行