基本线程机制
@(并发)[java, 并发, Thinking in Java]
- 单个进程可以拥有多个并发执行的任务,其底层机制是切分CPU时间
1. 定义任务
- 实现Runnable接口并编写run()方法
- 线程调度器:Thread.yield():Java线程机制的一部分,可以将CPU从一个线程转移给另一个线程,但是是选择性的
2. Thread类
Thread thread = new Thread(obj implements Runnable);
thread.start()
方法为线程执行必须的初始化操作,然后调用run()方法。
3. 使用Executor
java.util.concurrent
包的执行器(Executor)将管理Thread对象,执行任务。Executor允许管理异步任务的执行—-优选
ExecutorService executor = Executors.newCachedThreadPool();
executor.execute(obj implement Runnable);
executor.shutdown();//防止新任务提交给Executor
FixedThreadPool: 一次性预先执行代价高昂的线程分配,即限制线程的数量。
CachedThreadPool: 在程序执行过程中通常会创建与所需数量相同的线程,然后在回收旧线程时停止创建新线程
SingleThreadExecutor:线程数量为1的FixedThreadPool,会序列化所有提交给它的任务
4. 从任务中返回值–实现Callable接口
Callable接口是一种具有类型参数的泛型,它的类型参数表示的是从call()中返回的值,并且必须用ExecutorService.submit()调用。submit()方法会产生Future对象。
class MyClass implements Callable<String>{
}
ExecutorService executor = Executors.newCachedThreadPool();
Future<String> result = executor.submit(new MyClass());
5. 休眠
Thread.sleep(10);
TimeUnit.MILLISECONDS.sleep(10); //建议
6. 优先级
线程的优先级将该线程的重要性传递给调度器。调度器倾向于让优先权最高的线程执行。但优先级不会导致死锁。
优先级需要在run()方法的开头部分设定。
JDK有10个优先级,但是它与多数操作系统不能映射的很好,所以只建议使用MAX_PRIORITY, NORM_PRIORITY, MIN_PRIORITY三个等级
7. 让步
Thread.yield(): 暗示可以出让CPU给其它线程,但是没有任何机制会保证它将会被采纳。
8. 后台(daemon)线程
☞在后台提供通用服务的线程,并且这些线程并不属于程序中不可或缺的那部分。所以当所有非后台线程结束时,程序也就终止了,同时会杀死进程中所有的后台线程。
8.1 设置后台标志
//线程启动**之前**调用setDaemon()方法,才能将它设置为后台线程。
Thread daemon = new Thread(obj implement Runnable);
daemon.setDaemon(true);
daemon.start();
8.2. 定制ThreadFactory
public class DaemonThreadFactory implements ThreadFactory{
public Thread newThread(Runnable r){
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}
}
public static void main(String[] args){
ExecutorService executor = Executors.newCachedThreadPool(new DaemonThreadFactory());
executor.execute(obj implements Runnable);
}
Daemon线程派生出的子线程默认也为Daemon
9. 编码的变体
9.1. 直接继承Thread
public class MyThread extends Thread{
}
9.2. 自管理的Runnable
public class SelfManaged implement Runnable{
private Thread t = new Thread(this);
public SelfManaged(){
t.start();
}
public void run(){}
}
//该方法可能会访问到处于不稳定状态的对象。因为另一个任务可能会在构造器结束之前开始执行。
9.3. 匿名内部类
10. 术语
Thread类自身不执行任何操作,它只是驱动赋予它的任务
11. 加入一个线程
如果某个线程在另一个线程t上调用t.join(),此线程将被挂起,直到目标线程t结束才恢复(即t.isAlive()返回false)
join()方法可以带超时参数,这样如果目标线程在这段时间到期还没结束的话,join()方法返回。
12. 创建有响应的用户界面
13. 线程组 —-不成功的尝试
14. 捕获异常
问题:线程中不能捕获异常,一旦逃出任务的run()方法,就会向外传播到控制台。即使在main()方法中捕获也没用
package concurrency;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
/**
* ${DESCRIPTION}
*
* @author cinhori
* @version 1.0
* @since 2017-08-12 12:50
*/
public class CaptureUncaughtException {
public static void main(String[] args){
ExecutorService service = Executors.newCachedThreadPool(new HandlerThreadFactory());
service.execute(new ExceptionThread2());
}
}
class ExceptionThread2 implements Runnable{
@Override
public void run() {
Thread thread = Thread.currentThread();
System.out.println("run by " + thread.getName());
System.out.println("exceptionHandler: " + thread.getUncaughtExceptionHandler());
throw new RuntimeException();
}
}
class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("caught " + e.toString());
}
}
class HandlerThreadFactory implements ThreadFactory{
@Override
public Thread newThread(Runnable r) {
System.out.println(this + " creating new Thread");
Thread thread = new Thread(r);
System.out.println("creating " + thread);
thread.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
System.out.println("ExceptionHandler: " + thread.getUncaughtExceptionHandler());
return thread;
}
}
设置默认的未处理捕获异常处理器:
public class SettingDefaultHandler{
public static void main(String[] args){
Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
ExecutorService service = Executors.newCachedThreadPool();
service.execute(new ExceptionThread());
}
}