并发
并发主要解决:“速度” 和“设计可管理性” 问题
java的线程机制是抢占式的,表示 调度机制会周期性的中断线程,将上下文切换到另一个线程,从而为每个线程都提供时间片,使的每个线程都会分配到数量合理的时间去驱动它的任务。
Runnable接口描述任务,实际实现在run方法中。
Thread.yield()方法对线程调度器的调用的一种建议,表示通知cpu将一个线程转到另一个线程,但是不实际执行情况不一定会转到另一个线程上去。这是一种选择性的。
Thread类
使用方式:
Thread t = new Thread(new Runnable());
t.start();
每个Thread都会“注册”自己,自己引用自己,在它任务退出run()并且死亡之前,垃圾处理器无法回收它
Executor
用来管理Thread对象,允许管理异步任务的执行,无需显示的管理线程的生命周期
使用方式:
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new Runnable());
线程池:
CachedThreadPool : 每创建一个任务,创建一个线程,在程序执行过程中通常会创建与所需数量相同的线程,然后在它回收旧线程时停止创建新线程
FixedThreadPool :使用有限的线程来执行所提交的任务
SingleThreadExecutor :线程数量为1的FixedThreadPool,如果向SingleThreadExecutor提交多个任务,那么这些任务将会排队执行每个任务都会在下一个任务开始之前运行结束,所有的任务都将使用同一个线程。
从任务中返回值(Callable接口)
Runnable接口没有返回值,需要执行的任务返回结果,使用Callable接口(具有泛型的类型参数),它的类型参数表示的是从call()方法中返回的值,并切必须使用ExecutorService.submit()方法调用它。
使用方式:
//自定义callable接口
class IvyCallable implements Callable<String> {
public void IvyCallable(){}
public String call(){
return "返回期望返回的类型";
}
}
//demo
ExecutorService exec = Executors.newCachedThreadPool();
Feture<String> future = exec.submit(new IvyCallable());
submit()方法会产生Future对象,它用Callable返回结果的特定类型进行了参数化。可以使用Future.isDone()查询Future是否已经完成,任务完成时,调用Future.get()方法来获取任务执行的返回结果。可以不用isDone()进行检查就直接调用get(),这种情况下,gei()将阻塞,直至结果准备就绪。
线程优先级
线程的优先级将线程的重要性传递给调度器。cpu处理处理线程集的顺序是不确定的,但是调度器将倾向于优先级最高的线程优先执行。优先级较低的线程执行的频率较低。
getPriority()来读取现有线程的优先级,setPriority()设置线程优先级。在一个任务的内部,可以通过调用Thread.currentThread()来获的对驱动该任务的Thread对象的引用。
优先级 级别: MAX_PRIORITY、NORM_PRIORITY、MIN_PRIORITY
让步
给调度器一个暗示,表示任务已经执行的差不多了,可以让别的线程使用cpu了。但是不能保证一定会被采纳 ,通过调用yield()方法实现。
后台线程
含义:指在程序运行的时候在后台提供一种通用服务的线程,并且这种线程并不属于程序中不可或缺的部分。
只要有任务非后台线程还在运行,程序就不会终止。
设置后台线程:
thread daemon = new thread(new runanble());
daemon.setdaemon(true); //设置后台线程
daemon.start();
必须在线程启动前设置
可以通过isDaemon()方法来确定线程是否是一个后台线程,如果是一个后台线程,那么它创建的线程都被自动设置成后台线程。
后台线程不会执行finnally语句
加入一个线程
一个线程可以在其他线程之上调用join()方法,其效果是等待一段时间直到第二个线程结束才继续执行。