- 线程 run和start方法说明
run方法:其实是Runnable接口方法,只是个接口规范,业务逻辑都写在这个方法中(线程结束判断以及具体业务逻辑)
start方法:Thread 线程类封装的规范,一个线程实例只有调用了start方法,才能够开启新线程执行run。否则只调用run方法,实际并没有开启新的线程。start方法只能够调用一次,多次调用会报出异常 IllegalThreadStateException。start其实并不会开启线程,内部调用start0()方法才会真正的开启线程。
- 线程生命周期
从这个图中可以看到线程的状态流转,这里主要介绍线程的join和yield方法,后续会详细讲解notify和wait方法。
join 方法(获取CPU执行权):a线程调用b线程的join方法,就是把当前CPU执行权交给线程b,当执行完b线程后,才执行线程a。一般会用来控制多线程按照顺序执行(本来多线程是并行执行的),通过join方法可以控制每个线程的执行顺序。
yield方法(奉献出CPU执行权):调用a线程的yield方法,线程a就会进入就绪状态,CPU会从就绪线程集合中随机(有优先级)拿一个线程执行。当然拿到的这个线程也可能还是a线程,yield方法跟锁没有任何关系,并不是说释放锁。
- join方法案例,多任务按照顺序执行
- 无序
import java.util.Random;
public class xu02 {
private static class BuyTicket extends Thread{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"--正在购票--------");
try {
//模拟每个人购票时间不确定
Thread.sleep(new Random().nextInt(50));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"--购票完成--------");
}
}
public static void main(String[] args) {
//创建3个人排队购票
BuyTicket bird=new BuyTicket();
bird.setName("bird");
BuyTicket dog=new BuyTicket();
dog.setName("dog");
BuyTicket cat=new BuyTicket();
cat.setName("cat");
//1:无序购票(未排队),这里并不能够确定谁先买完票
cat.start();
dog.start();
bird.start();
}
}
- 指定顺序购票
package com.hongying.multithread;
import java.util.Random;
public class xu02 {
private static class BuyTicket extends Thread{
private Thread preThread;//排在他前面的人
public BuyTicket(Thread pre){
this.preThread=pre;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"--正在购票--------");
//做个判断,只有排在前面的人完成购票了才允许购票
if(preThread!=null){
try {
preThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
//模拟每个人购票时间不确定
Thread.sleep(new Random().nextInt(50));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"--购票完成--------");
}
}
public static void main(String[] args) {
//创建3个人排队购票
BuyTicket cat=new BuyTicket(null);//第一个位置
cat.setName("cat");
BuyTicket dog=new BuyTicket(cat);//第二个位置
dog.setName("dog");
BuyTicket bird=new BuyTicket(dog);//最后购票+
bird.setName("bird");
//有序购票,bird->dog->cat
bird.start();//尽管bird第一个开启购票,但是也会是最后一个结束购票
dog.start();
cat.start();
/*运行结果:
* dog--正在购票--------
*bird--正在购票--------
cat--正在购票--------
cat--购票完成--------
dog--购票完成--------
bird--购票完成--------
*/
}
}
- 守护线程和资源释放
守护线程:设置当前线程的setDaemon(true),默认创建线程是非守护线程;守护线程时,当主线程结束后,守护线程也跟着死亡。
资源释放:1、Object的finalize()方法,可以写资源释放,但是不推荐,有时不会执行。比如线程直接stop()
2、推荐 try-finally 资源释放,但是有个特列是当前线程是守护线程,主线程结束后,子线程如果不是interrupt 标志结束,子线程死亡有时不会调用finally 代码块。所以推荐不管是否是守护线程,线程结束都要使用 interrupt 标志 结束线程
代码案例:
package other.multithread;
/**
* @ClassName DaemonTest
* @Description des
* @Author zyk
* @Date 2019/9/26
* @Version 1.0
**/
public class DaemonTest {
private static class DaemonThread extends Thread {
@Override
public void run() {
try {
while (true) {
System.out.println("-----------working...------------");
if (Thread.currentThread().isInterrupted()) {
System.out.println("============线程结束==================");
break;
}
}
} finally {
//通过finally 进行资源释放;如果是守护线程,线程结束finally有时还是不会执行
System.out.println("=============finally-资源释放执行=============");
}
}
@Override
protected void finalize() throws Throwable {
//Object finalize 方法,可以完成资源释放,但是线程停止则有可能不会调到finalize()
System.out.println("=============finalize-资源释放执行=============");
}
}
public static void main(String[] args) throws InterruptedException {
DaemonThread daemonThread = new DaemonThread();
//设置守护进程后,开启线程的线程关闭后,守护线程也会结束;默认非守护线程
daemonThread.setDaemon(true);
daemonThread.start();
Thread.sleep(20);
//通过标志位暂停线程,如果不interrupt(),当前线程是守护线程,主线程结束子线程也跟着结束,此时finally中 资源释放有时就不会执行
//daemonThread.interrupt();
System.out.println("===========main线程结束=============");
}
}