一、Join线程
当前线程调用了 另一个线程的join() 方法,当前线程会阻塞,直到 被join的线程执行完成后 才会继续执行。
public class JoinThread extends Thread{
JoinThread(String name){
super(name);
}
@Override
public void run() {
super.run();
for (int i=0;i<100;i++){
Log.e("testthread",getName() +","+ i);
}
}
}
mBntFun4.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new JoinThread("新线程").start();
for (int i = 0;i<100;i++){
Log.e("testthread",Thread.currentThread().getName() +","+ i);
if (i == 20){
// 启动新线程
JoinThread joinThread = new JoinThread("join线程");
joinThread.start();
try {
//1. 调用新线程的join方法,当前线程会阻塞,知道join的线程执行完成
joinThread.join();
// 2.当前线程最多等待1毫秒,超过20毫秒Join的线程还没有执行完,则不再等待
//joinThread.join(1);
//3. 当前线程最多等待1毫秒加10毫微秒(一般不用这个,因为程序无法精确到毫微秒)
//joinThread.join(1,10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
说明
join方法有以上代码的三种重载方式
二、后台线程(守护线程、精灵线程)
- 有些线程在后台运行,为其他线程提供服务,比如JVM垃圾回收线程
- 当所有的前台线程死亡,那后台线程也会随之死亡,因为当前台进程都死亡后,就没有运行的必要了,虚拟机也就退出了,后台进程也就死亡了。
- 主线程默认是前台线程,前台线程创建的子线程是前台线程,后台线程创建的子线程是后台线程
- 调用线程的 setDaemon(true) 设置为后台线程
- 调用线程 isDaemon() 判断是否是后台线程
- setDaemon要在start()之前调用
class FirstThread extends Thread{
private int i;
@Override
public void run() {
super.run();
for (;i < 1000; i++){
Log.e("testthread",getName() +","+ i);
}
}
}
mBntFun5.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
FirstThread thread = new FirstThread();
// 要在start()之前调用
thread.setDaemon(true);
//启动线程
thread.start();
for (int i=0;i<10;i++){
Log.e("testthread",Thread.currentThread().getName() +","+ i);
}
// 主线程运行到这就结束了,后台线程也随之结束,所以thread并不会打印到 999
}
});
三、线程睡眠 :sleep(是Thread的静态方法)
可以让正在执行的线程暂停一段时间,进入阻塞状态
mBntFun5.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
for (int i=0;i<10;i++){
Log.e("testthread",Thread.currentThread().getName() +","+ new Date());
try {
//让主线程睡1毫秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
说明
从上面的运行结果可以看到,线程每隔一秒打印一次
- sleep也有两种重载方式:
- void sleep(long millis) : 暂停多少毫秒
- void sleep(long millis, int nanos):暂停多少毫秒加毫微秒(一般不用这个)
- 线程调用sleep()进入阻塞后,在睡眠时间内,不会获得执行的机会,即便系统中没有其他线程在执行,处于sleep状态的线程也不会执行
四、线程让步 :yield(静态方法)
可以暂停当前的线程,让它进入就绪状态,并不会阻塞该线程
class FirstThread extends Thread{
FirstThread(String name){
super(name);
}
@Override
public void run() {
super.run();
for (int i=0;i < 100; i++){
Log.e("testthread",getName() +","+ i);
if (i == 20){
Thread.yield();
}
}
}
}
mBntFun5.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
FirstThread thread1 = new FirstThread("高级");
thread1.setPriority(Thread.MAX_PRIORITY);
thread1.start();
FirstThread thread2 = new FirstThread("低级");
thread2.setPriority(Thread.MAX_PRIORITY);
thread2.start();
}
});
说明
- 通过**setPriority()**设置线程的优先级
- 调用yield()后,只有和当前线程同级或者比他优先级高的才会获得执行的机会
- 当没有比它优先级高的线程,调用yield()后当前线程继续执行
sleep()和yield()的区别:
- 优先级:sleep()调用后,不会理会其他线程的优先级;yield需要
- 状态:调用sleep()后会进入阻塞状态,经过阻塞事件才会进入就绪状态;而yield直接就进入就绪状态了
- 异常:调用sleep后会抛出InterruptedException异常,而yield没有抛出任何异常
- 可移植性:sleep()有更好的可移植性,**不建议用yield()来控制并发线程
五、改变线程的优先级
- 每个线程的优先级都和创建它的父线程优先级相同
- main线程具有普通优先级
- 设置优先级:
setPriority(1~10)
public static final int MAX_PRIORITY = 10;
public static final int MIN_PRIORITY = 1;
public static final int NORM_PRIORITY = 5;
- 返回优先级:
getPriority()