多线程复习
1.进程和线程
1.1定义
(1)进程:操作系统中一个程序的执行周期
(2)线程:进程中的一个任务。一个进程中可以包含n个线程(main()->主线程)
1.2进程与线程的关系
- 每个进程拥有自己的一整套变量,是操作系统中资源分配的最小的单位。
线程依托于进程存在,多个线程共享进程的资源,os中任务调度的基本单位。
- 启动、撤销一个进程的开销要比启动、撤销以一个线程大的多(线程轻量级)
- 进程间通信远比线程间通信复杂的多;
- 没有进程就没有线程,进程一旦终止,其内的线程全部取消;
1.3线程的状态
2.多线程实现
Java中创建线程的四种方式:
(1)继承Thread类
(2)实现Runnable接口
(3)实现Callable接口
(4)使用线程池(推荐)
2.1继承Thread类
java.lang.Thread是线程操作的核心类
2.1.1出现版本
JDK1.0
2.1.2实现方法
直接继承Thread类而后覆写类中的run()方法(相当于主方法,一个线程的入口就是run方法)
无论哪种方式实现多线程,线程启动一律调用Thread类提供的start()方法。
2.1.3start()方法解析
1.首先检查线程状态是否为0(线程默认状态为0表示为启动),如果线程已经启动再次调用start()方法会抛出IllegalThreadStateException异常。所以一个线程的start()方法只能调用一次。
2.private native void start0();通过start0()方法真正将线程启动。
3.JVM调用start0()方法进行资源分配与系统调度,**准备好资源启动线程后回调run()**来执行线程的具体任务!
2.1.4线程启动调用方法流程
start()->start0()->JVM_StartThread()->run_method_name()->run()
2.1.5局限性
单继承问题
2.2实现Runnable接口
java.lang.Runnable
2.2.1出现版本
JDK1.0
2.2.2实现方法
Java中Thread类本身也实现了Runnable接口,与用户自定义的线程类共同组成代理设计模式
其中Thread类实现辅助操作,包括线程的资源调度等任务;自定义线程类完成真实业务·
实现Runnable接口,覆写run()
public Thread(Runnable target){}
public static void main(String[] args) {
MyThread1 mt1 = new MyThread1();
MyThread1 mt2 = new MyThread1();
MyThread1 mt3 = new MyThread1();
Thread t1 = new Thread(mt1);
Thread t2 = new Thread(mt2);
Thread t3 = new Thread(mt3);
t1.start();
t2.start();
t3.start();
}
2.2.3继承Thread类与实现Runnable接口区别
- 继承Thread类有单继承局限,相对而言实现Runnable接口更加灵活,并且Thread类本身也实现了Runnable辅助真实业务类
- 实现Runnable接口可以更好的实现程序共享的概念(Thread类也可以,)
2.3实现Callable接口
java.util.concurrent
2.3.1出现版本
JDK1.5
2.3.2实现方法
实现Callable接口,覆写call()方法
Future:可接收call()方法的返回值
public static void main(String[] args) throws ExecutionException, InterruptedException {
//1.产生Callable对象
MyThread3 mt = new MyThread3();
//2.产生FutureTask对象
FutureTask<String> ft = new FutureTask<>(mt);
new Thread(ft).start();
new Thread(ft).start();
new Thread(ft).start();
//3.接收call()返回值,FutureTask的get()继承自Future接口中的get()
System.out.println(ft.get());
}
2.3.3实现Runnable接口与实现Callable接口的区别
- 实现Callable接口,线程执行任务后有返回值;而实现Runnable接口,线程执行后没有返回值
3.多线程常用方法
3.1线程的命名与取得
- 取得当前JVM正在执行的线程对象:public static native Thread currentThread();
- 线程命名:
- 创建线程时设置名称:public Thread (Runnable target,String name)
- 设置线程名称:public final synchronized void setName(String name)
- 取得线程名:public final String getName()
3.2线程休眠
3.2.1定义
让线程暂缓执行,等到了预计时间再回复执行
public static native void sleep(long millis) throws InterruptedException{};
3.2.2状态变换
运行状态---->阻塞状态---->休眠结束---->就绪状态
3.2.3注意
(1)线程休眠会立即交出CPU,让CPU去执行其他任务。线程休眠不会释放对象锁;
(2)多个线程进入一个方法,不是同时休眠的;
3.3线程让步
3.3.1定义
暂停当前正在执行的线程对象,并执行其他线程
public static native void yield();
3.3.2状态变换
运行状态<---->就绪状态
3.3.3注意
(1)yield()会让当前线程交出CPU,但不一定会立即交出。yield()交出CPU后只能让拥有相同优先级的线程有获取CPU的机会,不会释放对象锁
3.4线程等待
3.4.1定义
等待该线程终止。
若线程1需要等待线2执行完毕后再恢复执行,可以在线程1中调用线程2的join();在哪个线程调用,哪个线程阻塞,等待线程执行完毕再恢复执行
3.4.2状态转换
运行状态->阻塞状态->就绪状态
3.4.3注意
(1)join()方法只是对Object类wait()做了一层包装而已;
(2)交出cpu,释放对象锁
3.5线程停止
3.5.1三种方式停止线程
-
设置标记位,可以使线程正常退出(推荐)
-
使用stop方法强制让线程退出,但是该方法不安全已经被@Deprecated
-
使用Thread类提供的interrupt()中断线程(就是系统设置了一个标记位,直接使用即可)
interrupt方法只是将线程状态改为中断状态而已,它不会中断一个正在运行的线程;
3.5.2设置标记位
class MyThread02 implements Runnable{
private int books = 0;
private boolean flag = true;
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
while (flag == true){
System.out.println(Thread.currentThread().getName()+"卖出书号:"+(books--));
}
System.out.println("线程停止");
}
}
public class test02 {
public static void main(String[] args) throws InterruptedException {
MyThread02 mt1 = new MyThread02();
Thread t1 = new Thread(mt1);
t1.start();
Thread.sleep(1000);
mt1.setFlag(false);
}
}
3.5.3stop方法
强行关闭线程,不管有没有执行完循环(不推荐使用)
废弃的原因:不安全,stop()会解除由线程获得的所有锁定,当在一个线程对象上调用了stop(),这个线程对象所运行的线程就会立即停止,可能会产生不完整数据信息
3.5.4interrupt()方法
调用interrupt()
-
如果在线程中没有调用wait() sleep() join(),则标记线程(isInterrupt = true);
并不会真正中断线程,只是简单的将线程的状态置为interrupt而已,我们可以根据此状态来进一步确定如何处理线程;
Thread类提供的public boolean isInterrupted()可以检测当前线程状态是否为中断状态
class MyThread1 implements Runnable{
boolean flag = true;
@Override
public void run() {
int i = 0;
while (flag){
boolean bool = Thread.currentThread().isInterrupted();
if(bool){
System.out.println("线程进入中断状态");
return;
}
System.out.println("当前线程状态为"+bool);
System.out.println(Thread.currentThread().getName()+","+(i++));
}
System.out.println("线程停止");
}
}
public class threadInterrupt {
public static void main(String[] args) throws InterruptedException {
MyThread1 mt1 = new MyThread1();
Thread thread = new Thread(mt1);
thread.start();
Thread.sleep(1000);
thread.interrupt();
}
}
一秒后设置线程状态为中断状态,调用isInterrupt()返回值为true,进入if语句,执行操作,输出线程进入中断状态&#