操作线程有很多种方法,这些方法可以使线程从某一种状态过度到另一种状态。
sleep()–线程休眠
sleep()方法是Thread类中的一个静态方法,需要一个用于指定该线程休眠的时间,该时间以毫秒为单位。
在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
例如:
public class Test {
static class MyThread implements Runnable {
@Override
public void run() {
int i = 10;
// TODO Auto-generated method stub
while(i >= 0) {
System.out.println(Thread.currentThread().getName() + "-->" + i--);
if (i == 6) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) {
new Thread(new MyThread(),"MyThread").start();
int i = 10;
while(i >= 0) {
System.out.println(Thread.currentThread().getName() + "-->" + i--);
}
}
}
运行结果:
上面的代码中name为“MyThread”的线程在i等于6的时候进入了休眠状态,从运行的结果也可以看到,在i大于6之前一直是main线程和MyThread线程交替运行,当MyThread线程中的i变为6的时候,该线程暂停了运行,一段时间后又恢复了运行。
注意:
1、使用了sleep()方法的线程在休眠时间过后会醒来,即进入到就绪状态,但是不能保证能立即被执行。
2、由于sleep()方法有可能抛出InterruptedException异常,所以将sleep()方法的调用放在try–catch块中。
join()–线程加入
如果当前线程为多线程程序,加入存在一个线程A,现需要插入一个线程B,并要求线程B先执行完毕,然后再继续执行线程A,此时可以使用Thread类中的join()方法来完成。这就好比此时你正在一边看电视,一边吃饭,突然你妈妈要求你必须先先吃完饭才能继续看电视。
当某个线程使用join()方法加入到另外一个线程时,另外一个线程会等待该线程执行完毕后再继续执行。
也可以向join()方法中传入参数,表示等待该线程终止的时间最长为 millis 毫秒(+ nanos 纳秒),如果时间到了,加入的线程还没执行完毕,CPU则会重新调度。
例如:
public class Test {
public static void main(String[] args) {
/**
* Having dinner Thread
*/
Thread thread01 = new Thread(new Runnable() {
public void run() {
int i = 0;
// TODO Auto-generated method stub
while (i <= 10) {
System.out.println(Thread.currentThread().getName() + "-->" + i * 10 + "%");
i++;
}
}
}, "Having dinner");
/**
* Watching TV Thread
*/
new Thread(new Runnable() {
public void run() {
int i = 0;
// TODO Auto-generated method stub
while (i <= 10) {
System.out.println(Thread.currentThread().getName() + "-->" + i * 10 + "%");
i++;
if (i == 6) {
try {
thread01.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}, "Watching TV").start();
//启动线程01
thread01.start();
}
}
运行结果:
上述例子中创建了两个线程,分别是“Having dinner Thread”和“Watching TV Thread”,一开始两个线程交替执行,在“Watching TV Thread”执行到60%时,在“Watching TV Thread”中加入线程“Having dinner Thread”,此时“Watching TV Thread”必须等待“Having dinner Thread”执行完毕后才能继续执行。
注意:如果任何线程中断了加入的线程则抛出InterruptedException异常。当抛出该异常时,当前线程的中断状态被清除。
yield()–线程礼让
Thread类中有一个静态方法yield(),表示线程礼让,当前线程放弃执行权,再度回到就绪状态,给其他线程有进入执行状态的机会。
当前线程执行yield()方法放弃执行权重回就绪状态,此时CPU会重新调度,所以该线程任然有可能继续执行。
例如:
public class Test {
public static void main(String[] args) {
Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName() + " --> start");
Thread.yield();
System.out.println(Thread.currentThread().getName() + " --> end");
}
},"ThreadA");
Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName() + " --> start");
System.out.println(Thread.currentThread().getName() + " --> end");
}
},"ThreadB");
threadA.start();
threadB.start();
}
}
运行结果:
线程的终止
在以前的jdk版本中,曾经提供过destroy()方法和stop()方法来让线程提前终止,但是这两个方法因为有bug,已经被废弃了,不推荐使用。
destroy()方法最初用于破坏该线程,但不作任何清除。它所保持的任何监视器都会保持锁定状态。不过,该方法决不会被实现。即使要实现,它也极有可能以suspend()方式被死锁。如果目标线程被破坏时保持一个保护关键系统资源的锁,则任何线程在任何时候都无法再次访问该资源。如果另一个线程曾试图锁定该资源,则会出现死锁。这类死锁通常会证明它们自己是“冻结”的进程。
而用Thread.stop终止线程将释放它已经锁定的所有监视器(作为沿堆栈向上传播的未检查 ThreadDeath 异常的一个自然后果)。如果以前受这些监视器保护的任何对象都处于一种不一致的状态,则损坏的对象将对其他线程可见,这有可能导致任意的行为。
stop的许多使用都应由只修改某些变量以指示目标线程应该停止运行的代码来取代。目标线程应定期检查该变量,并且如果该变量指示它要停止运行,则从其运行方法依次返回。例如:
public class Test {
static class MyThread implements Runnable {
int i = 0;
boolean flag = true;
@Override
public void run() {
// TODO Auto-generated method stub
while (flag == true) {
System.out.println(i++);
if (i == 9) {
flag = false;
}
}
}
}
public static void main(String[] args) {
new Thread(new MyThread()).start();
}
}
运行结果: