目录
Thread类及常见方法
Thread类的常见构造方法
Thread的几个常见属性
线程的启动-start()
start()使用示例
start()与run()的区别?
等待一个线程-join()
获取当前线程
休眠当前线程
线程的中断
Thread类是JVM用来管理线程的一个类,即每个线程都有一个唯一的Thread对象与之关联
· 线程构造方法的使用
用来创建线程,具体的使用介绍在上篇博客有提到:创建线程的方式
Thread t1 = new Thread();
Thread t2 = new Thread(new MyRunnable());
Thread t3 = new Thread("线程1");
Thread t4 = new Thread(new MyRunnable(), "线程2");
首先创建一个线程并启动,用来演示下列属性的获取方法
public class getAttribute {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while(true){}
}
});
t.start();
}
}
· ID:ID是线程的唯一标识,不同线程不会重复
获取方法:getID()
System.out.println(t.getId());
· 名称:名称是在各种调试工具中用到的
获取方法:getName()
System.out.println(t.getName());
· 状态:状态表示线程当前所处的一个情况,本篇博客后面会详细讲述.
获取方法:getState()
System.out.println(t.getState());
· 优先级:优先级高的线程理论上来说更容易被调度到
获取方法:getPriority()
System.out.println(t.getPriority());
· 是否为后台线程:JVM会在一个进程的所有非后台线程结束后,才会结束运行
获取方法:isDaemon()
System.out.println(t.isDaemon());
· 是否存活:简单理解为run方法是否结束运行
获取方法:isAlive()
System.out.println(t.isAlive());
thread.start():申请系统调度,执行thread中的任务(重写的run方法).
例如,利用Thread类实例化一个线程t,利用t调用start方法.
public class StartRun {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("t线程启动");
}
},"t线程");
t.start();
}
}
补充:main方法的执行,也是存在一个main线程,在上述程序中main线程执行利用Thread创建t线程的代码,但main线程不会执行run方法,run方法是t线程执行的.
①start是启动线程的方式
②run是属于线程任务的描述
以如下代码来介绍start和run到底哪个是启动线程的方式
· 线程对象.run,属于普通对象的实例方法调用,并没有启动线程,此时一直是main线程在运行
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("t线程 run");
}
},"t线程");
t.run();
}
· 多个线程,同时存在并发和并行现象,下述代码同时存在main线程和t线程,main线程:①new Runnable对象、②new Thread对象、③t.start()、④执行输出语句;t线程:t线程在启动线程后调用run方法.
public class StartRun {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("t线程 run");
}
},"t线程");
t.start();
System.out.println("t线程 start,main");
}
}
在多线程的应用中,经常会需要等待一个线程完成它的工作后,才能进行自己的下一步工作.例如转账,假如A给B转账,只有等到A成功转账给B后,B才能决定是否存钱,这时就需要一个方法来明确等待线程的结束.
· join():t线程一直运行态,main线程一直等待态
例如:
public class ThreadJoin {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("t线程 run");
while(true){}
}
},"t线程");
t.start();
t.join();
System.out.println("t线程start 这是main线程");
}
}
· join(millis):等待线程运行结束,最多等待millis毫秒,例如下列代码,t线程先打印,然后一直运行,main线程等3秒打印,然后结束.
public class ThreadJoin {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("t线程 run");
while(true){}
}
},"t线程");
t.start();
t.join(3000);
System.out.println("t线程start 这是main线程");
}
}
假如目前有t线程和main线程,拿上述两个示例为例:
①t线程一直处于运行态,而main线程处于等待状态
②t线程先打印,然后一直运行,main线程等待3秒后执行打印,然后结束,此时t线程一直也处于运行态.
当前线程一般指的是某行代码所在的线程,它返回的是当前线程的引用对象.
//返回当前线程对象的引用
public static Thread currentThread();
public class CurrentThread {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
},"子线程").start();
System.out.println(Thread.currentThread().getName());
}
}
直接利用Thread类名.sleep即可,让当前线程休眠(超时等待)指定时间,具体用法如下:
public class Sleep {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
},"子线程");
t.start();
}
}
程序运行起来3秒后打印出当前线程的名称.
· 使用自定义的变量来作为标志位
需要给标志位上加volatile关键字,自定义标志位如果当线程处于等待/超时等待/阻塞,就没办法中断了
public class ThreadDemo {
private static volatile boolean isInterrupt = false;
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
for(int i = 0; i<10 && !isInterrupt; i++) {
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
t.start();
Thread.sleep(3000);
isInterrupt = true;
}
}
· 使用Thread.interrupted()或者Thread.currentThread().isInterrupted()代替自定义标志位
Thread内部包含了一个boolean类型的变量作为线程是否被中断的标记
例如下列代码
public class ThreadDemo1 {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
while(!Thread.currentThread().isInterrupted()) {
for (int i = 0; i < 10; i++) {
System.out.println(i);
Thread.sleep(1000);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("出现异常时中断标志位:>" + Thread.currentThread().isInterrupted());
}
}
});
t.start();
Thread.sleep(3000);
t.interrupt();
}
}
在调用api中断时,即使线程处于等待状态,也会被直接中断.