四、多线程编程 (4.1)
- 操作系统管理的基本单元:进程
- 操作系统调度的最小单元:线程(轻量级进程)
- 在一个进程中可以创建多个线程,并且这些线程有着各自的计数器、堆栈和局部变量,还可以访问共享的内存变量
- 多线程的意义:减少程序响应时间,使程序具备更好的交互性、线程创建和切换的开销更小、提高多核CPU的利用率,避免造成资源浪费、简化程序结构,易于维护
- 线程状态:
- New: 创建状态,还未调用start方法
- Runnable:可运行状态,调用了start方法,可能正在运行也可能没有运行,取决于操作系统给线程提供的时间
- Blocked:阻塞状态,暂时不活动
- Waiting:等待状态,暂时不活动且不运行任何代码,消耗资源最少
- Timed Waiting:超时等待,可以在指定的时间内返回
- Terminated:终止状态,线程执行完毕,可能为run方法执行完毕正常退出,也可能因为一个没有捕获的异常而终止
Thread本质是Runnable接口的一个实例,实现多线程的三种方法:
1. 继承Thread类,重写run方法
public class TestThread extends Thread{
public void run(){
System.out.println("hello world");
}
public static void main(String[] args){
Thread mThread = new TestThread();
mThread.start();
}
}
2. 实现Runnable接口,并实现该接口的run方法
public class TestRunnable implements Runnable{
public void run(){
System.out.println("hello world");
}
}
public class TestRunnable {
public static void main(String[] args) {
TestRunnable mTestRunnable = new TestRunnable();
Thread mThread = new Thread(mTestRunnable);
mThread.start();
}
}
3. Callable接口,重写call方法: 与方法2类似但是提供了比方法2更强大的功能比如可以在任务接受后提供返回值,call方法可以抛出异常
public class TestCallable {
public static class MyTestCallable implements Callable {
public String call() throws Exception {
return "hello world";
}
}
public static void main(String[] args){
MyTestCallable mMyTestCallable =new MyTestCallable();
ExcecutorService mExcecutorService = Excecutors.newSingleThreadPool();
Future mfuture = mExecutorService.submit(mMyTestCallable);
try {
System.out.println(mfuture.get());
} catch (Exception e){
e.printStackTrace();
}
}
}
线程中断:可以调用Thread.currentThread().isInterrupted()来看线程是否被置位,还可以调用Thread.interrupted()对中断标志位进行复位,但是线程处于阻塞状态时无法检测中断状态,此时如果中断标志位=true,会抛出InterruptedException异常,且在抛出异常前将线程的中断标志位复位为false,不能在底层代码中捕捉到异常而不处理:
void myTask() {
try{
sleep(50)
} catch(InterruptedExcetion e){
}
}
有两种处理方式:
1. 不捕捉这样的异常,让方法直接抛出,这样的话调用者可以捕获此异常:
void myTask() throws InterruptedException{
sleep(50)
}
2. catch中调用Thread.interrupt()来设置中断状态,让外界通过Thread.isInterrupted来判断是否终止线程:
void myTask() {
try{
sleep(50)
} catch(InterruptedExcetion e){
Thread.currentThread.interrupt();
}
}