并发
并发是基于多核处理器编程的基本工具。
通常是用来提高单处理器上的程序的性能。从性能的角度看,如果没有任务阻塞,单处理器机器上使用并发就没有什么意义。
实现并发最简单的操作就是在系统级别使用进程。进程是运行在它自己的地址空间内的自包容的程序。
多任务操作系统通过周期性地将CPU从一个进程切换到另一个进程,来实现同时运行多个程序。java的并发系统会共享诸如内存和I/O这样的资源,因此并发最基本的困难在于协调不同进程驱动的任务之间对这些资源的使用,以使得这些资源不会同时被多个任务访问。
java在顺序语言的基础上提供了对线程的支持,线程是在由执行程序表示的单一进程中分配任务,具有操作系统透明性。
协作多线程:java的线程机制是抢占式的,这表示调度机制会周期性地中断线程,将上下文切换到另一个线程,从而为每个线程都提供时间片,使得每个线程都分配到数量合理的时间去驱动它的任务。
基本的线程机制
并发编程使得我们可以将程序划分为多个分离的,独立运行的任务。这些任务中的每一个都由一个执行线程来驱动。线程就是进程中的一个单一的顺序控制流。
底层机制:CPU时间切片
- 定义任务:通过实现Runnable接口并实现run()方法来定义任务。
- Thread类:将Runnable对象转变为工作任务的传统方式是将它提交给一个Thread构造器,然后调用Thread的start()方法为该线程执行必须的初始化操作,然后调用Runnable的run()方法来在新线程中启动任务。
每个线程在创建的时候注册了自己,因此存在一个对它的引用,直至它的任务退出其run()并死亡之前,垃圾回收器无法清除它。 - 使用Executor:java.lang.concurrent包中的执行器Executor会管理Thread类对象,从而简化并发编程。Executor在客户端和线程之间提供了一个中间层,由中介对象取代客户端直接执行任务。它允许管理异步任务的执行,而无须显示地管理线程的生命周期。
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new Runnable对象);
它为每一个任务创建一个线程。shutDown()方法可以防止新任务被提交给这个Executor。
FixedThreadPool:有限的线程集,可以一次性预先执行代价高昂的线程分配操作,限制了线程的数量,节省了时间以及为每个任务创建线程的开销。
CachedThreadPool:在程序执行过程中通常会创建与所需数量相同的线程,然后在回收线程的时候停止创建新的线程。
SingleThreadExecutor相当于数量为1的FixedThreadPool。如果提交了多个任务,会进入排队。
在任何线程池中,现有线程在可能的情况下,都会被自动复用。 - 实现Callable接口:Runnable接口是执行工作的独立任务,但是它不返回任何值。Callable是一种具有类型参数的泛型,它的类型参数表示的是从call()接口返回的值,并且必须使用ExecutorService.submit()方法调用。submit方法会产生Future对象,它用Callable返回结果的特定类型进行了参数化,可以使用isDone()来查询Future是否已经完成,也可以直接调用get()(还未完成的话会堵塞直至完成)
- 休眠:sleep(),使任务中止执行给定的时间。
- 优先级: 调度器会让优先级较高的线程执行,优先级较低的线程仅仅是执行的频率较低,但并不是不执行。优先级是在run()开头设定的。唯一可移植的优先级是只设置MAX_PRIORITY、 NORM_PRIORITY和MIN_PRORITY三种。
- 让步:yield()方法,建议相同优先级的线程可以运行。
- 后台线程:在程序运行的时候,在后台提供一种通用服务的线程。并且这种线程并不属于程序中不可或缺的部分。因此,当程序中所有的非后台进程结束时,程序也就终止了,同时会杀死进程中的后台线程。必须在线程启动之前调用setDaemon()方法将其设置为后台进程。后台进程在不执行finally语句的情况下就会终止其run方法,因为一旦main退出,JVM会立即关闭所有后台线程。
- 继承Thread类
10.join()方法:如果一个线程在另一个线程t上调用join(),那么该线程将被挂起,直到线程t结束才恢复(即t.isAlive()返回false的时候)。
也可以在调用join()带上一个超时参数,如果目标线程在这段时间到期时还没结束,join()方法总能返回。
对join()方法的调用可以被中断,就是在调用线程上调用interrupt()方法,这时需要用到try-catch语句。 - 捕获异常:由于线程的本质特性,使得你不能捕获从线程中逃逸的异常。jAVA SE5提供了新接口:Thread.UncaughtExceptionHandler。