这篇文章介绍Thread类的方法,包含Thread类的静态方法和实例方法,有关yield、sleep和Object类的wait方法的比较放在Lock里对比介绍。
1、run()和start()
这两个方法的对比在《创建线程的方法》里的Thread类里介绍了。
2、yield()
Thread类的静态方法,调用后能让当前线程释放CPU的时间片,进入就绪状态(而非阻塞状态),让与该线程有同等优先级的其他线等待线程获取CPU执行权,也有可能当前线程又重新获得CPU时间片进入运行状态,调用yield方法不会使线程释放它所持有的对象的同步锁。
3、sleep(sec)
Thread类的静态方法,调用后能使线程由运行状态进入休眠阻塞状态。入参为休眠时间,单位为毫秒,超过休眠时间后,线程会由休眠阻塞状态进入就绪状态,等待CPU时间片重新进入运行状态。sleep方法不会释放当前线程所持有的的对象的锁。
4、中断
java中断相关的有3个方法,stop()方法已经不推荐使用了。
void interrupt()
- Thread类实例方法,向线程发送中断请求,将线程的中断状态置为true,但不会中断(停止)这个正在运行的线程,类似“set”。
- 当线程处于阻塞状态(比如调用了sleep方法),此时再调用该线程的interrupt()方法,会抛出InterruptedException中断异常,不会将线程的中断状态再置为true。
boolean isInterrupted()
- Thread类的实例方法,用来返回线程的中断状态,调用这一方法不会改变线程的中断状态,类似“get”。
static boolean interrupted()
Thead类的静态方法,返回线程的中断状态,同时会产生副作用:将线程的中断状态置为false,类似“get”+”set”。
从上面的叙述可以看出,这三个方法并不能真正的将一个线程中断,只能改变线程的中断状态(boolean值),改变了线程的中断状态后,再由实际代码判断到底要不要停止当前线程(return掉也行),因此这个中断状态可以被用来当做标志位(开关),我们可以通过if或者while这种判断语句来决定线程中断状态置为true后该怎么处理,举个例子:
public class MyThread extends Thread{
@Override
public void run() {
while (!this.isInterrupted())
{
System.out.println("当前线程没有被中断,继续干活");
}
System.out.println("当前线程被被中断,停止干活");
}
}
public class ConcurrentOneMain {
public static void main(String[] args) {
Thread t = new MyThread();
t.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
t.interrupt();
}
}
上面程序中,MyThread类里通过while(!this.isInterrupted())来对中断状态置为true的线程处理,当中断状态为true,跳出while循环,打印”当前线程被被中断,停止干活”,当为false时继续执行while循环体里语句,打印”当前线程没有被中断,继续干活”。main方法里主线程会先休眠5秒,再对MyThread实例线程进行中断,运行结果如下:
...
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程被被中断,停止干活
开始的5秒内MyThread线程运行run()方法,循环打印“继续干活”,主线程对MyThread线程调用interrupt方法后,将MyThread线程t的中断状态置为true,结束while循环,打印“停止干活”,然后MyThread线程t的run()方法执行结束。
当MyThread线程t处于休眠阻塞状态时,主线程对其调用interrupt方法,会抛出InterruptedException,举个例子:
public class MyThread extends Thread{
@Override
public void run() {
while (!this.isInterrupted())
{
System.out.println("当前线程没有被中断,继续干活");
try {
Thread.sleep(1000);
} catch (InterruptedException e)
{
this.interrupt();
}
}
System.out.println("当前线程被被中断,停止干活");
}
}
修改上面的MyThread类,main方法不变,在while循环里给每次循环sleep一秒,模拟当MyThread类的实例线程t正在sleep(1000)时,主线程给t interrupt了。这时会抛出InterruptedException异常,但是不会将MyThread类的实例t的中断状态置为true,因此在catch子句里还要对线程t进行interrupt,主动将t的中断状态置为true,这是才能跳出while循环 ,结束run()方法。
5、join()/join(sec)
Thread类的实例方法,t.join()方法阻塞调用此方法的线程,直到线程t完成,此线程再继续,可以将程序由异步执行转变为串行执行。通常用于让主线程等待子线程运行后再执行。
举个例子:
public class MyThread extends Thread{
@Override
public void run() {
String currentThreadName = Thread.currentThread().getName();
System.out.println(currentThreadName + "开始运行");
for(int i = 0; i < 20; ++i)
{
System.out.println( currentThreadName + "正在运行 " + String.valueOf(i));
}
}
}
public class ConcurrentOneMain {
public static void main(String[] args) {
Thread t = new MyThread();
t.start();
System.out.println("主线程开始运行");
for(int i = 0; i < 20; ++i)
{
System.out.println("主线程正在运行 " + String.valueOf(i));
}
}
}
上面是个异步执行的例子,MyThread t和主线程各自执行各自的 ,结果如下:
...
主线程正在运行 15
Thread-0正在运行 14
主线程正在运行 16
Thread-0正在运行 15
主线程正在运行 17
Thread-0正在运行 16
主线程正在运行 18
Thread-0正在运行 17
主线程正在运行 19
Thread-0正在运行 18
Thread-0正在运行 19
但当在主线程里调用t.join()方法后,主线程会先等待t线程执行完,再执行主线程里的方法,main方法如下:
public class ConcurrentOneMain {
public static void main(String[] args) {
Thread t = new MyThread();
t.start();
try{
t.join();
} catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println("主线程开始运行");
for(int i = 0; i < 20; ++i)
{
System.out.println("主线程正在运行 " + String.valueOf(i));
}
}
}
结果如下,将异步执行转换为串行执行:
...
Thread-0正在运行 14
Thread-0正在运行 15
Thread-0正在运行 16
Thread-0正在运行 17
Thread-0正在运行 18
Thread-0正在运行 19
主线程开始运行
主线程正在运行 0
主线程正在运行 1
主线程正在运行 2
主线程正在运行 3
主线程正在运行 4
主线程正在运行 5
...
6、Thread类的其他方法
currentThread()
Thread类的静态方法,返回当前线程的实例对象。
getID()
用来得到线程ID。
getName和setName
用来得到或者设置线程名称。
getPriority和setPriority
用来获取和设置线程优先级。
setDaemon和isDaemon
用来设置线程是否成为守护线程和判断线程是否是守护线程。