一、线程控制基本方法
1、表格
2、sleep方法
1)可以调用Thread的静态方法:
public static void sleep(long millis)
throws InterruptedException
使得当前线程休眠(暂时停止执行millis毫秒)
2)由于是静态方法,sleep可以由类名直接调用:
Thread.sleep(...);
在哪个线程中调用该方法,就会使得哪个线程休眠。
3)例子:
package com.hpe.thread;
import java.util.Date;
public class TestInterrupt {
public static void main(String[] args) {
Mythread thread = new Mythread(); //主线程创建了一个线程thread
thread.start(); //主线程让thread进入就绪态,当thread进入运行态时,就会调用自己的run()方法
try {
Thread.sleep(5000); //主线程睡眠5秒,sleep()方法必须使用try-catch来捕捉
} catch (InterruptedException e) { }
thread.interrupt(); //主线程执行中断thread线程
}
}
class Mythread extends Thread {
@Override
public void run() {
while(true) {
System.out.println("===" + new Date() + "==="); //thread线程打印当前日期和时间
try {
sleep(1000); //每打印一次,睡眠1秒
} catch (InterruptedException e) {
System.out.println(getName() + "被中断!");
return;
}
}
}
}
运行结果:
===Tue Mar 07 14:43:56 CST 2017===
===Tue Mar 07 14:43:57 CST 2017===
===Tue Mar 07 14:43:58 CST 2017===
===Tue Mar 07 14:43:59 CST 2017===
===Tue Mar 07 14:44:00 CST 2017===
Thread-0被中断!
总结:
1)子类重写父类方法时所抛出的异常不能不同于父类方法所抛出的异常。
2)当父类方法没有抛出异常时,子类重写该方法时也不能抛异常。
3)1和2中,如果子类重写的方法中可能出现异常,只能通过try-catch来捕捉异常。
4)在哪个线程中调用sleep()方法,就让哪个线程睡眠。
5)run()方法的结束意味着线程的终止。
6)interrupt()方法本身并不能使线程结束。
其实interrupt()方法只是用于触发一个正在休眠的线程发生中断异常,然后我们在捕获到异常后决定要退出run()方法,从而达到结束线程的目的。
7)在线程无休眠操作时,interrupt()方法无法导致异常发生,则没有任何效果。
补充:
1)对于一些资源还没来得及关闭的线程,上述的run()方法的实现有些粗暴,一种使用标志位的方法使用的也比较广泛,这种方法保证即使线程被中断,也至少能把本次循环中要做的事都完成,不过个人觉得把关闭资源的代码写在finally中不就可以了吗,这样不用标志位这种方法也可以。
class Mythread extends Thread {
private boolean flag = true;
@Override
public void run() {
while(flag) {
System.out.println("===" + new Date() + "==="); //thread线程打印当前日期和时间
try {
sleep(1000); //每打印一次,睡眠1秒
} catch (InterruptedException e) {
flag = false;
System.out.println(getName() + "被中断!");
}
}
}
}
2)如果一个进程在睡眠,那么一定使用了try-catch来捕捉可能发生的中断异常,我们可以在catch语句中使用标志位的方法来结束本次循环,如果不需要关闭额外的资源的话,我们甚至可以直接return,就算后续要关闭某些资源,也可以将用于关闭资源的代码写在finally语句块中,当run()方法中没有调用sleep()方法的时候,可以使用下面这种标志位法更为简便,这是不通过interrupt()方法来结束线程的方法。
package com.hpe.thread;
public class TestThread3 {
public static void main(String[] args) {
Runner4 r = new Runner4();
Thread t = new Thread(r);
t.start();
for(int i=0; i<100000; i++) {
if(i % 10000 == 0 && i > 0) {
System.out.println("in thread main i = " + i);
}
}
r.shutdown();
System.out.println("thread main is over");
}
}
class Runner4 extends Thread {
private boolean flag = true;
@Override
public void run() {
int i = 0;
while(flag) {
System.out.println(" " + i++);
}
}
public void shutdown() {
flag = false;
}
}
3、join方法
jion用于合并某个线程。
package com.hpe.thread;
public class TestJoin {
public static void main(String[] args) {
MyThread1 t1 = new MyThread1("t1");
t1.start();
try {
t1.join();
} catch (InterruptedException e) {}
for(int i=1; i<=10; i++) {
System.out.println("I am main thread");
}
}
}
class MyThread1 extends Thread {
public MyThread1(String name) {
super(name);
}
@Override
public void run() {
for(int i=1; i<=10; i++) {
System.out.println("I am " + getName());
try {
sleep(1000);
} catch (InterruptedException e) {
return;
}
}
}
}
运行结果:
I am t1
I am t1
I am t1
I am t1
I am t1
I am t1
I am t1
I am t1
I am t1
I am t1
I am main thread
I am main thread
I am main thread
I am main thread
I am main thread
I am main thread
I am main thread
I am main thread
I am main thread
I am main thread
4、yield方法
使线程会让出CPU,进入就绪队列等待下一次调度。
package com.hpe.thread;
public class TestYield {
public static void main(String[] args) {
MyThread3 t1 = new MyThread3("t1");
MyThread3 t2 = new MyThread3("t2");
t1.start();
t2.start();
}
}
class MyThread3 extends Thread {
public MyThread3(String name) {
super(name);
}
@Override
public void run() {
for(int i=0; i<100; i++) {
System.out.println(getName() + ": " + i);
if(i % 10 == 0) {
yield();
}
}
}
}
总结:
当任意一个线程打印到10的整数倍时,都会把当前CPU的使用权让出来,让另一个线程运行。