前言:这里讲的线程都不采用线程池,继承Thread类和实现Runnable以及Callable都通过Thread来创建并启动,即这里的线程控制都是指Thread的方法
线程控制(即Thread类)主要有5个方法
- join线程:join()
- 后台线程:setDaemon()
- 线程睡眠:sleep()
- 线程让步:yield()
- 改变线程优先级:setPriority()
一. join线程
join线程指:让一个线程等待另一个线程完成。
1. join():等待线程执行完成
当在A线程中调用B线程的join()方法时,调用线程(A线程)将被阻塞,直到B线程执行完为止。
2. join(long millis):等待被join的线程最长时间为millis毫秒
在A线程里调用B线程的join(long millis)方法,A将被阻塞,阻塞时间不超过millis。假如B线程需要10*1000毫秒才执行完毕,而millis为5000,那么B执行5秒后,A和B都回到就绪状态
3. join(long millis,int nanos): 等待被join的线程最长时间为millis毫秒+nanos毫微秒
该方法忽略不用
public class JoinCallable implements Callable {
private int i=0;
@Override
public Object call() throws Exception {
for (;i<5;i++){
Log.d("MainActivity",Thread.currentThread().getName()+" i:"+i);
Thread.sleep(100);
}
return null;
}
}
//使用
private void joinCallable() {
try {
for (int i=0;i<6;i++){
Log.d("MainActivity",Thread.currentThread().getName()+":"+i);
if (i==3){
Callable joinCallable = new JoinCallable();
FutureTask task = new FutureTask(joinCallable);
Thread thread = new Thread(task, "join线程");
thread.start();
thread.join();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//运行打印日志
2020-05-04 22:49:24.264 31878-31878/priv.hsj.thread D/MainActivity: main:0
2020-05-04 22:49:24.265 31878-31878/priv.hsj.thread D/MainActivity: main:1
2020-05-04 22:49:24.265 31878-31878/priv.hsj.thread D/MainActivity: main:2
2020-05-04 22:49:24.265 31878-31878/priv.hsj.thread D/MainActivity: main:3
2020-05-04 22:49:24.267 31878-31914/priv.hsj.thread D/MainActivity: join线程 i:0
2020-05-04 22:49:24.368 31878-31914/priv.hsj.thread D/MainActivity: join线程 i:1
2020-05-04 22:49:24.469 31878-31914/priv.hsj.thread D/MainActivity: join线程 i:2
2020-05-04 22:49:24.569 31878-31914/priv.hsj.thread D/MainActivity: join线程 i:3
2020-05-04 22:49:24.671 31878-31914/priv.hsj.thread D/MainActivity: join线程 i:4
2020-05-04 22:49:24.777 31878-31878/priv.hsj.thread D/MainActivity: main:4
2020-05-04 22:49:24.777 31878-31878/priv.hsj.thread D/MainActivity: main:5
注意:join方法必须要在start方法后调用才有效
二. 后台线程
后台线程是在后台运行的,为其他的线程提供服务,他也叫”守护线程“和”精灵线程♀️“。
JVM的垃圾回收线程就是典型的后台线程。
如果所有的前台线程都死亡,后台线程就会自动死亡。
Thread类还提供了isDaemon()方法,用于判断指定线程是否为后台线程。
注意:setDaemon(true)必须必须要在start()方法前调用,否则会IllegalThreadStateException异常。
三. 线程睡眠
线程睡眠是让当前正在执行的线程暂停一段时间,即阻塞一段时间
- sleep(long millis):让当前正在执行的线程暂停millis毫秒,并进入阻塞状态
- sleep(long millis,int nanos):让当前正在执行的线程暂停millis毫秒加nanos毫微秒。该方法忽略不用。
当前线程调用sleep()方法进入阻塞状态后,在其睡眠时间段内,该线程不会获得执行的机会,即使系统中没有其他可执行的线程,处于sleep()中的线程也不会执行。
sleep()时间过完后,由阻塞状态转为就绪状态
四. 线程让步
线程让步是将线程转入就绪状态
当前线程调用yield()方法进入就绪状态,线程调度器重新调度
线程调用yield()方法后将执行机会让给优先级相同,或优先级更高的线程
sleep()与yield方法区别
- sleep()是将线程转入阻塞状态。yield()是将该线程转入就绪状态
- sleep()期间,会给其他线程执行机会,其他所有线程机会平等,与优先级无关。yield()只会给优先级相同或优先级更高的线程执行机会,即有可能某个线程调用yield()方法暂停之后,会立即再次获得CPU
- sleep()方法声明抛出异常,而yield()没有声明抛出异常。
- sleep()比yield()有更好的可移植性,并发线程一般不会使用yield()
五. 改变线程优先级
每个线程执行时都具有一定的优先级,优先级高的线程获得较多的执行机会,优先级低的获得较少的执行机会。
每个线程默认的优先级都与创建它的父线程的优先级相同。
setPriority(int newPriority)方法参数取值范围为1~10,默认为5,Thread类给了三个静态常量
- MAX_PRIORITY:值为10
- MIN_PRIORITY:值为1
- NORM_PRIORITY:值为5
在开发中,尽量避免使用具体数字,应使用三个静态常量,这样更具有移植性。
上一篇:Android多线程(二)——线程的生命周期:https://www.jianshu.com/p/0b9468cda0c7