sleep方法(线程休眠)
sleep(long millis)作用是让当前线程休眠指定的毫秒,使当前线程进入阻塞状态,期间会让出cpu的资源,但不会释放已获得的锁.
到达指定时间后,线程会从阻塞状态变成 可运行状态,重新竞争cpu的资源
static void sleep(long millis)
这是Thread类中的静态方法。这里提到“当前线程”的概念,谈谈我的理解:
关于“当前线程”的理解:
即Thread.currentThread()返回的线程,也可以说是正在执行sleep方法的线程。
下面来看个例子:
public class myThread03 extends Thread{
public void run(){
System.out.println(this.getName());
System.out.println(Thread.currentThread().getName());
}
public static void main(String[]args){
myThread03 mt0 = new myThread03();
myThread03 mt1 = new myThread03();
mt0.start();
mt1.start();
}
}
这里创建并启动了两个线程,两个线程都分别执行run方法里的语句。当 Thread-0 线程访问run方法时,Thread-0对于被访问的run方法来说就是当前线程。当然,线程都是并发执行的,Thread-1线程同时也在访问run方法,那么对于被Thread-1访问的run方法,Thread-1就是当前线程。 所以,当前线程不能从字面上理解为某个时间段里正在运行的线程,因为线程都是并发的,一段时间内有多个线程在同时执行。
现在来看看 sleep方法的实例:
public class myThread3 extends Thread {
@Override
public void run(){
try{
System.out.println("begin = " + System.currentTimeMillis());
System.out.println(Thread.currentThread().getName()+"开始执行");
//使线程休眠2000ms
Thread.sleep(2000);// 使用该静态方法需要捕获一个名为InterruptedException的异常
System.out.println(Thread.currentThread().getName()+"结束执行");
System.out.println("end = " + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args)
{
myThread3 mt = new myThread3();
mt.start();
}
}
运行可以看到,“开始休眠”和“休眠结束”之间隔了2秒钟,即 2000毫秒。
线程中断
void interrupt();//像线程发送中断请求,线程的中断状态将被设置成true。如果目前该线程被一个sleep调用堵塞,那么,就会抛出InterruptedException异常
static boolean interrupted() //测试当前线程是否被中断,注意,这是一个静态的方法。而且这一调用会产生副作用:它会将当前的线程的中断状态重置为false。
boolean isInterrupted() //测试线程是否被中断,这一调用不改变线程的中断状态
调用interrupt()方法后,线程中断,该线程就不能继续执行了。
来看下面这个例子:
public class myThread05 extends Thread {
public void run(){
int num = 0;
while (isInterrupted()==false){ // 如果线程中断状态为false,则一直执行
System.out.println("第"+num+"次执行");
num++;
}
}
public static void main(String[] args) throws InterruptedException {
myThread05 mt = new myThread05();
mt.start();
Thread.sleep(200); // 让主线程休眠0.2秒,子线程继续执行
mt.interrupt(); // 申请中断线程,中断状态设置为true
}
}
yield方法 (线程让步)
暂时执行当前线程,并让出cpu资源(不会释放锁).当前线程会进入等待列表,和等待列表中的其他线程重新一起竞争cpu的资源
所以执行yield方法的效果等价于当前线程把cpu时间片用完,从运行状态返回到就绪状态
public class myThread05 extends Thread {
public void run(){
long begin = System.currentTimeMillis();
for (int i=0;i<50000000;i++){
Thread.yield(); //线程暂停,让出cpu资源,重新开始执行的时间不确定
}
long end = System.currentTimeMillis();
long time=end-begin;
System.out.println(Thread.currentThread().getName()+ "执行完毕,花费时间为"+ time);
}
public static void main(String[] args) throws InterruptedException {
myThread05 mt = new myThread05();
myThread05 mt1 = new myThread05();
myThread05 mt2 = new myThread05();
mt.start();
mt1.start();
mt2.start();
}
}
运行结果如下:
耗费的时间很长,三个线程的执行耗费的时间差距也很大。(可以把for循环里的 Thread.yield() 删除重新运行,运行结果差别很大)
join方法 (线程合并)
暂停当前线程的运行,等待指定线程完成后在执行当前线程,执行起来的效果就好像是把指定线程合并到了当前线程.
void join(); 等待该线程终止
void join(long millis);等待该线程终止,等待的时间最长为 millis 毫秒。
注意点:
- join方法必须在线程start方法调用之后才有意义
- join方法可以传入一个参数,如 在A线程中调用 B.join(10),表示A线程会等待B线程10ms后运行,10ms后,A、B线程并行执行.join()等价于join(0),表示A线程等待B线程无限时间,直到B线程执行结束
- A线程调用 B.join()后,在B线程执行过程中,如果A线程发送了中断会抛出异样(但如果B中断不会报异常)
- join内部实现是调用wait()方法实现,所以调用join方法会释放锁
例子: 要求创建 a,b,c三个线程,并规定让 线程a,线程b,线程c顺序执行完成
public class myThread5 extends Thread {
@Override
public void run() {
try {
System.out.println("线程a开始执行");
Thread.sleep(500);
System.out.println("线程a结束执行");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
myThread5 a =new myThread5();
Thread b = new Thread(()->{
try {
System.out.println("线程b开始执行");
//执行完a线程,再继续往下执行
a.join();
System.out.println("线程b结束执行");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread c = new Thread(()->{
try {
System.out.println("线程c开始执行");
//执行完b线程,再继续往下执行
b.join();
System.out.println("线程c结束执行");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
a.start();
b.start();
c.start();;
}
}