文章目录
目录
六、getName()及setName(String name)方法
七、getPriority()及setPriority(int newPriority)方法
九、sleep(long millis)、sleep(long millis, int nanos) 方法
十二、interrupt()、isInterrupted()、interrupted()方法
前言
本文章记录Thread方法中的常用方法的用法
一、常见方法汇总
方法名 | 功能说明 | |
---|---|---|
start() | 启动一个新线程,在新的线程运行run方法中的代码 | start 方法只是让线程进入就绪,里面代码不一定立刻运行(CPU 的时间片还没分给它)。每个线程对象的start方法只能调用一次,如果调用了多次会出现IllegalThreadStateException |
run() | 新线程启动后会调用的方法 | 如果在构造 Thread 对象时传递了 Runnable 参数,则线程启动后会调用 Runnable 中的 run 方法,否则默认不执行任何操作。但可以创建 Thread 的子类对象,来覆盖默认行为 |
join() | 等待线程运行结束 | |
join(long millis) | 等待线程运行结束,最多等待 millis毫秒 | |
join(long millis,int nanos) | 等待线程运行结束,最多等待 millis毫秒,nanos纳秒 | |
getId() | 获取线程长整型的 id | id 唯一 |
getName() | 获取线程名 | |
setName(String name) | 修改线程名 | |
getPriority() | 获取线程优先级 | |
setPriority(int newPriority) | 修改线程优先级 | java中规定线程优先级是1~10 的整数,较大的优先级能提高该线程被 CPU 调度的机率 |
static yield() | 提示线程调度器让出当前线程对CPU的使用 | 主要为了调试和测试 |
static sleep(long millis) | 使得当前线程阻塞millis毫秒 | |
static sleep(long millis, int nanos) | 使得当前线程阻塞millis毫秒加上nanos纳秒 | |
static currentThread() | 获取当前正在执行的线程 | |
isAlive() | 判断线程存活状态 | |
interrupt() | 打断线程 | 如果被打断线程正在 sleep,wait,join 会导致被打断的线程抛出 InterruptedException,并清除 打断标记 ;如果打断的正在运行的线程,则会设置 打断标记 ;park 的线程被打断,也会设置 打断标记 |
isInterrupted() | 判断是否被打断 | 不会清除打断标记 |
static interrupted() | 判断当前线程是否被打断 | 会清除打断标记 |
getState() | 获取线程状态 |
Java 中线程状态是用 6 个 enum 表示,分别为: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED |
二、start方法
1.演示代码
Thread t1 = new Thread("t1") {
@Override
public void run() {
log.debug("running...");
}
};
t1.start();
t1.start();
/**
* 结果
* Exception in thread "main" java.lang.IllegalThreadStateException
* at java.lang.Thread.start(Thread.java:705)
* at cn.itcast.test.Test5.main(Test5.java:17)
* 17:48:15.878 c.Test5 [t1] - running...
*/
2.说明
2.说明
通过start源码可以看出,当第二次调用start的时候 threadStatus等于5,即不等于0所以就抛出IllegalThreadStateException异常。start方法中最核心的就是调用了start0()方法,而start0 源码为:private native void start0();jvm会调用native方法执行线程run方法。
三、run()方法
1、演示代码
public static void main(String[] args) {
Thread t1 = new Thread("t1") {
@Override
public void run() {
log.debug("running 继承方式...");
}
};
t1.run();
t1.start();
Thread t2 = new Thread(()->{
log.debug("running Runnable接口实现方式...");
},"t2");
t2.run();
t2.start();
/**
* 结果:
* 19:24:12.739 c.Test5 [main] - running 继承方式...
* 19:24:12.742 c.Test5 [t1] - running 继承方式...
* 19:24:12.772 c.Test5 [main] - running Runnable接口实现方式...
* 19:24:12.773 c.Test5 [t2] - running Runnable接口实现方式...
*/
}
2、说明
如果通过线程对象直接调用run方法,那么就只是调用了一个普通的run方法,不会启动多线程。只有通过start方法才能启动线程,run方法是由jvm调用的。Thread方法中的run方法的源代码如下所示:
如果通过继承的方式创建线程并重写run方法,那么jvm调用的是子类的run方法,Thread类中的run方法就没什么意义。如果通过实现Runnable接口的方式实现多线程,那么就会调用Thread中的run方法,该方法的逻辑很简单,就是判断一下传入Thread类中Runnable接口实现类对象target是否为空,如果不为空就调用该对象的run方法。target是Thread中的成员变量,当创建线程时,把Runnable接口的实现类对象传到Thread构造函数中,该构造函数会调用内部私有方法init进行赋值
public Thread(Runnable target, String name) {
init(null, target, name, 0);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc) {
if (name == null) {
//如果线程名字为空,则抛出异常,这也说明线程都要由名字
throw new NullPointerException("name cannot be null");
}
this.name = name;
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */
/* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
}
/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
}
/* checkAccess regardless of whether or not threadgroup is
explicitly passed in. */
g.checkAccess();
/*
* Do we have the required permissions?
*/
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
g.addUnstarted();
this.group = g;
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext =
acc != null ? acc : AccessController.getContext();
//target 成员变量赋值
this.target = target;
setPriority(priority);
if (parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
tid = nextThreadID();
}
四、join()、join(n)、join(n,m)方法
1、演示代码
public static void main(String[] args) throws InterruptedException {
log.debug("开始");
Thread t1 = new Thread(() -> {
log.debug("开始");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("结束");
r = 10;
},"t1");
t1.start();
t1.join();
log.debug("结果为:{}", r);
log.debug("结束");
/**
* 不使用join()方法时候的结果为:
* 21:27:50.683 c.Test10 [main] - 开始
* 21:27:50.714 c.Test10 [t1] - 开始
* 21:27:50.714 c.Test10 [main] - 结果为:0
* 21:27:50.715 c.Test10 [main] - 结束
* 21:27:51.720 c.Test10 [t1] - 结束
* 使用join()方法后的结果
* 21:28:55.345 c.Test10 [main] - 开始
* 21:28:55.378 c.Test10 [t1] - 开始
* 21:28:56.380 c.Test10 [t1] - 结束
* 21:28:56.380 c.Test10 [main] - 结果为:10
* 21:28:56.382 c.Test10 [main] - 结束
*/
}
2、说明
join方法的作用是主线程(调用join方法线程)等待子线程(被调用join方法的线程)的终止。也就是说主线程的代码块中,如果碰到了t.join()方法,此时主线程需要等待(阻塞),等待子线程结束了 ,才能继续执行t.join()之后的代码块。对应上边演示代码就是当main线程执行到t1.join()的时候,需要等待t1线程执行完成后再继续执行后边的代码。join()与join(n)方法的区别,就是当主线程等待n毫秒后,如果子线程还没执行完那么主线程也不会等待了。如果子线程执行时间小于n,那么子线程执行完成后主线程立马就可以执行。至于join(n,m)带两个参数的方法其实相比较join(n)没有多大区别,因为join(n,m)内部也调用join(n),具体细节看源码
public final void join() throws InterruptedException {
//调用带有一个形参的join方法
join(0);
}
public final synchronized void join(long millis, int nanos)
throws InterruptedException {
//对参数millis合法性进行检查,如果小于0那么该参数为非法参数就会抛出异常
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
//对参数nanos 合法性进行检查,如果小于0那么该参数为非法参数就会抛出异常
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
//如果纳秒数大于等于500000或者毫秒数为0但是纳秒数不为0,那么把毫秒数参数millis加1
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
//调用只有一个参数的join方法,此时millis最多比调用该方法时多1毫秒
join(millis);
}
public final synchronized void join(long millis)
throws InterruptedException {
//记录当前时间毫秒数
long base = System.currentTimeMillis();
//定义变量now,变量nowjoin代表该join方法已经执行的毫秒数
long now = 0;
//对参数合法性进行检查,如果小于0那么该参数为非法参数就会抛出异常
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
//如果参数等于0
if (millis == 0) {
//只要该线程处于活动状态那么进入while循环体
while (isAlive()) {
//如果该线程还存活,那么调用该线程join方法的线程,就会被置为阻塞状态(TIMED_WAITING)
wait(0);
}
} else {
//如果参数不等于0,其实到这一步就代表参数大于0
//只要该线程处于活动状态那么进入while循环体
while (isAlive()) {
//计算参数millis与now的差值
long delay = millis - now;
//如果差值delay小于等于零(主线程阻塞的时间大于等于millis 毫秒),
//那么就执行break,即跳出循环,
//这也就代表这join方法执行完毕
if (delay <= 0) {
break;
}
//主线程阻塞(TIMED_WAITING)dealy毫秒,
//但此时主线程可能在小于dealy毫秒的时候被唤醒
wait(delay);
//无论主线程是等待时间够了,还是在等待的中途被打断了
//now 变量都会被重新赋值,值为当前时间毫秒数减去刚进入该方法的时间数
//即now变量代表着join方法已经执行的毫秒数
//赋值完成后会继续进行下一轮的while循环
now = System.currentTimeMillis() - base;
}
}
}
当主线程调用t1线程的join方法,那么此时主线程就会获得线程对象t1的锁,带主线程被wait后那么主线程会让出cpu及线程对象t1的锁。
如果线程t1还没有调用start方法启动,就调用t1的jion方法,是无效的,因为此时t1线程的isAlive()为false,即该线程还不是处于活动状态,此时就不会阻塞主线程。
五、getId()方法
1、演示代码
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread("t1"){
@Override
public void run() {
log.debug("运行多线程");
}
};
log.debug(t.getId()+"");
t.start();
log.debug(t.getId()+"");
/**
* 结果:
* 23:21:42.040 c.Test1 [main] - 20
* 23:21:42.042 c.Test1 [main] - 20
* 23:21:42.043 c.Test1 [t1] - 运行多线程
*/
}
2、说明
无论该线程是否启动,该线程的id都已经生成了。这是因为当创建线程对象时,构造方法会调用内部的init方法,该方法中就对线程id做了赋值,也就是说线程对象创建后线程id就有值了。
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc) {
/* Set thread ID */
tid = nextThreadID();
}
private static synchronized long nextThreadID() {
return ++threadSeqNumber;
}
/* For generating thread ID */
private static long threadSeqNumber;
public long getId() {
return tid;
}
init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc)方法完整代码在上边说明run()方法时已经展示了完整的代码了,所以此处省略一些代码,getId方法其实就是返回了Thread成员变量tid的值,而tid的值在init中被赋值。其实tid的值就是Thread 静态成员变量threadSeqNumber值加1,应为threadSeqNumber为静态的所以这也就能解释为什么该线程的id不是1而是20的原因了。
六、getName()及setName(String name)方法
1、演示代码
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(){
@Override
public void run() {
log.debug("运行多线程");
}
};
log.debug(t.getName());
t.setName("t1");
log.debug(t.getName());
t.start();
/**
* 结果:
* 23:40:02.851 c.Test1 [main] - Thread-0
* 23:40:02.853 c.Test1 [main] - t1
* 23:40:02.854 c.Test1 [t1] - 运行多线程
*/
}
2、说明
getName()及setName(String name)做用就是获取线程名字和设置线程名字
public final String getName() {
return name;
}
public final synchronized void setName(String name) {
checkAccess();
//参数检查
if (name == null) {
throw new NullPointerException("name cannot be null");
}
//成员变量name重新赋值
this.name = name;
//如果threadStatus不等于0,即该线程对象已经创建了并启动了
if (threadStatus != 0) {
//设置线程名称
setNativeName(name);
}
}
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
public Thread(String name) {
init(null, null, name, 0);
}
线程可以通过setName命名,也可以在创建线程的时候直接命名,如果线程没有刻意的命名,那么jdk会给该线程命名,命名规则为”Thread-” + nextThreadNum()
七、getPriority()及setPriority(int newPriority)方法
1、演示代码
public static void main(String[] args) {
Runnable task1 = () -> {
int count = 0;
for (;;) {
System.out.println("---->1 " + count++);
}
};
Runnable task2 = () -> {
int count = 0;
for (;;) {
System.out.println(" ---->2 " + count++);
}
};
Thread t1 = new Thread(task1, "t1");
Thread t2 = new Thread(task2, "t2");
t1.setPriority(Thread.MIN_PRIORITY);
t2.setPriority(Thread.MAX_PRIORITY);
t1.start();
t2.start();
/**
* 不设置优先级部分结果
*
* ---->1 1697629
* ---->1 1697630
* ---->1 1697631
* ---->2 1100251
* ---->2 1100252
*设置优先级后部分结果
* ---->1 1024957
* ---->1 1024958
* ---->1 1024959
* ---->2 2245023
* ---->2 2245024
* ---->2 2245025
*/
}
2、说明
getPriority()是返回该线程的优先级,setPriority(int newPriority)是设置线程的优先级,通过演示代码可以看出,对于优先级高的线程,执行的机率就会低一些,但这不代表低优先级的线程不能被执行。也不能代表低优先级的线程一定是在高优先级的线程后边执行。线程创建时会继承父线程的优先级。
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc) {
Thread parent = currentThread();
this.priority = parent.getPriority();
setPriority(priority);
}
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
//对参数进行校验
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
//如果当前线程的线程组不为空
if((g = getThreadGroup()) != null) {
//如果传入的优先级大于线程组中线程优先级最大值
if (newPriority > g.getMaxPriority()) {
//newPriority 重新赋值为当前线程组中线程优先级的最大值
newPriority = g.getMaxPriority();
}
//调用本地方法,设置线程的优先级,并且把Thread成员变量重新赋值为newPriority
setPriority0(priority = newPriority);
}
}
public final int getPriority() {
return priority;
}
/**
* The minimum priority that a thread can have.
* 最小优先级
*/
public final static int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to a thread.
* 默认优先级
*/
public final static int NORM_PRIORITY = 5;
/**
* The maximum priority that a thread can have.
* 最大优先级
*/
public final static int MAX_PRIORITY = 10;
八、yield() 方法
1、演示代码
public static void main(String[] args) {
Runnable task1 = () -> {
int count = 0;
for (;;) {
System.out.println("---->1 " + count++);
}
};
Runnable task2 = () -> {
int count = 0;
for (;;) {
Thread.yield();
System.out.println(" ---->2 " + count++);
}
};
Thread t1 = new Thread(task1, "t1");
Thread t2 = new Thread(task2, "t2");
t1.start();
t2.start();
/**
*运行结果:
* ---->2 221719
* ---->2 221720
* ---->1 520559
* ---->1 520560
*/
}
2、说明
public static native void yield();
调用 yield 会让当前线程从 Running 进入 Runnable 就绪状态,把执行机会让给优先级相同或更高的线程,如果队列中没有同优先级的线程则忽略此方法。
九、sleep(long millis)、sleep(long millis, int nanos) 方法
1、演示代码
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread("t1") {
@Override
public void run() {
log.debug("enter sleep...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
log.debug("wake up...");
e.printStackTrace();
}
log.debug("enter sleep end...");
}
};
t1.start();
log.debug("main thread run...");
/**
* 运行结果:
* 07:42:41.349 c.Test7 [main] - main thread run...
* 07:42:41.349 c.Test7 [t1] - enter sleep...
* 07:42:43.362 c.Test7 [t1] - enter sleep end...
*/
}
2、说明
通过时间戳可以看出sleep起作用,调用sleep会让当前线程从 Running 进入Timed Waiting 状态(阻塞),睡眠结束后的线程未必会立刻得到执行。sleep(long millis)方法也为本地方法。
public static native void sleep(long millis) throws InterruptedException;
public static void sleep(long millis, int nanos)
throws InterruptedException {
//参数合法性校验,如果millis小于0则会抛出异常
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
//参数合法性校验,nanos如果小于0,或者大于999999则抛出异常
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
//如果nanos大于等于500000 或者毫秒数为0但纳秒数不为0则millis加1
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
//调用本地方法sleep(long millis),此时毫秒数最多比原有形参数多1毫秒
sleep(millis);
}
十、currentThread() 方法
1、演示代码
public static void main(String[] args) throws InterruptedException {
Thread thread = Thread.currentThread();
thread.setName("main 线程");
log.debug("main 运行,,,,");
//结果:08:00:32.071 c.Test8 [main 线程] - main 运行,,,,
}
2、说明
currentThread方法也是本地方法
public static native Thread currentThread();
十一、isAlive() 方法
1、演示代码
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread("t1"){
@Override
public void run() {
log.debug("run 方法里:"+String.valueOf(Thread.currentThread().isAlive()));
try {
Thread.sleep(2000);
log.debug("t1主线程睡眠后:"+String.valueOf(Thread.currentThread().isAlive()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
log.debug("线程对象创建后:"+String.valueOf(t.isAlive()));
t.start();
log.debug("线程调用start后:"+String.valueOf(t.isAlive()));
Thread.sleep(3000);
log.debug("主线程睡眠1S后:"+String.valueOf(t.isAlive()));
/**
* 运行结果:
* 08:31:45.926 c.Test8 [main] - 线程对象创建后:false
* 08:31:45.928 c.Test8 [main] - 线程调用start后:true
* 08:31:45.928 c.Test8 [t1] - run 方法里:true
* 08:31:47.944 c.Test8 [t1] - t1主线程睡眠后:true
* 08:31:48.940 c.Test8 [main] - 主线程睡眠1S后:false
*/
}
2、说明
isAlive()方法判读线程是否存活(还没有运行完毕)该方法也是本地方法
public final native boolean isAlive();
十二、interrupt()、isInterrupted()、interrupted()方法
1、演示代码
//打断阻塞状态
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
log.debug("sleep...");
try {
Thread.sleep(5000); // wait, join
} catch (InterruptedException e) {
log.debug("sleep interrupt....");
log.debug("sleep 之后打断标志:{}",Thread.currentThread().isInterrupted());
e.printStackTrace();
}
},"t1");
t1.start();
log.debug("interrupt");
t1.interrupt();
/**
* 结果:
* 20:59:31.757 c.Test11 [main] - interrupt
* 20:59:31.757 c.Test11 [t1] - sleep...
* 20:59:31.761 c.Test11 [t1] - sleep interrupt....
* 20:59:31.761 c.Test11 [t1] - sleep 之后打断标志:false
* java.lang.InterruptedException: sleep interrupted
* at java.lang.Thread.sleep(Native Method)
* at cn.itcast.test.Test11.lambda$main$0(Test11.java:13)
* at java.lang.Thread.run(Thread.java:745)
*/
}
//打断正常运行的线程
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
while(true) {
boolean interrupted = Thread.currentThread().isInterrupted();
log.debug("线程"+Thread.currentThread().getName()+"在运行");
if(interrupted) {
log.debug("被打断了, 退出循环");
break;
}
}
}, "t1");
t1.start();
log.debug("interrupt");
t1.interrupt();
/**
* 运行结果:
* 21:24:11.495 c.Test12 [main] - interrupt
* 21:24:11.495 c.Test12 [t1] - 线程t1在运行
* 21:24:11.498 c.Test12 [t1] - 线程t1在运行
* 21:24:11.498 c.Test12 [t1] - 被打断了, 退出循环
*/
}
private static void test4() {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
log.debug("park..."+i);
LockSupport.park();
// Thread.interrupted()会清除打断标志
log.debug("打断状态:{}", Thread.interrupted());
//如果打断标记已经是 true, 则 park 会失效
// log.debug("打断状态:{}", Thread.currentThread().isInterrupted());
}
});
t1.start();
sleep(1);
t1.interrupt();
//如果打断标记已经是 true, 则 park 会失效
/**
* 运行结果:
*21:39:03.888 c.Test14 [Thread-0] - park...0
* 21:39:04.896 c.Test14 [Thread-0] - 打断状态:true
* 21:39:04.898 c.Test14 [Thread-0] - park...1
* 21:39:04.898 c.Test14 [Thread-0] - 打断状态:true
* 21:39:04.898 c.Test14 [Thread-0] - park...2
* 21:39:04.898 c.Test14 [Thread-0] - 打断状态:true
* 21:39:04.898 c.Test14 [Thread-0] - park...3
* 21:39:04.898 c.Test14 [Thread-0] - 打断状态:true
* 21:39:04.898 c.Test14 [Thread-0] - park...4
* 21:39:04.898 c.Test14 [Thread-0] - 打断状态:true
*/
//Thread.interrupted()会清除打断标志
/**
*21:41:19.075 c.Test14 [Thread-0] - park...0
* 21:41:20.081 c.Test14 [Thread-0] - 打断状态:true
* 21:41:20.083 c.Test14 [Thread-0] - park...1
*/
}
private static void test3() throws InterruptedException {
Thread t1 = new Thread(() -> {
log.debug("park...");
LockSupport.park();
log.debug("unpark...");
log.debug("打断状态:{}", Thread.currentThread().isInterrupted());
}, "t1");
t1.start();
sleep(1);
t1.interrupt();
/**
* 运行结果:
* 21:34:59.118 c.Test14 [t1] - park...
* 21:35:00.132 c.Test14 [t1] - unpark...
* 21:35:00.133 c.Test14 [t1] - 打断状态:true
*/
}
2、说明
处于阻塞的线程,即在执行Object对象的wait()、wait(long)、wait(long, int),或者线程类的join()、join(long)、join(long, int)、sleep(long)、sleep(long,int)方法后线程的状态,当线程调用interrupt()方法后,这些方法将抛出InterruptedException异常,并清空线程的中断状态,即isInterrupted()返回false,也就是说interrupt()可以中断阻塞状态,但是要注意的interrupt()方法不是中断线程执行,如果想要通过interrupt()方法中断线程,那就需要配合着isInterrupted()方法,通过代码逻辑来实现,可以参考着上边的演示代码中的“打断正常运行的线程”的代码。另外isInterrupted()、interrupted() 两个方法都可以查看线程是否被打断,但不同的是interrupted()返回是否被打断后,会清除打断标记。 通过如下代码可以理解两个方法区别:
private static void test4() {
Thread t1 = new Thread(() -> {
for (int i = 0; i <3; i++) {
log.debug("park..."+i);
//如果打断标记已经是 true, 则 park 会失效
log.debug("打断状态isInterrupted1:{}", Thread.currentThread().isInterrupted());
LockSupport.park();
// Thread.interrupted()会清除打断标志
log.debug("打断状态:{}", Thread.interrupted());
log.debug("打断状态isInterrupted2:{}", Thread.currentThread().isInterrupted());
Thread.currentThread().interrupt();
log.debug("打断状态isInterrupted3:{}", Thread.currentThread().isInterrupted());
}
});
t1.start();
sleep(1);
t1.interrupt();
/**
* 运行结果:
* 22:10:00.242 c.Test14 [Thread-0] - park...0
* 22:10:00.244 c.Test14 [Thread-0] - 打断状态isInterrupted1:false
* 22:10:01.252 c.Test14 [Thread-0] - 打断状态:true
* 22:10:01.252 c.Test14 [Thread-0] - 打断状态isInterrupted2:false
* 22:10:01.252 c.Test14 [Thread-0] - 打断状态isInterrupted3:true
* 22:10:01.252 c.Test14 [Thread-0] - park...1
* 22:10:01.252 c.Test14 [Thread-0] - 打断状态isInterrupted1:true
* 22:10:01.252 c.Test14 [Thread-0] - 打断状态:true
* 22:10:01.252 c.Test14 [Thread-0] - 打断状态isInterrupted2:false
* 22:10:01.252 c.Test14 [Thread-0] - 打断状态isInterrupted3:true
* 22:10:01.252 c.Test14 [Thread-0] - park...2
* 22:10:01.252 c.Test14 [Thread-0] - 打断状态isInterrupted1:true
* 22:10:01.252 c.Test14 [Thread-0] - 打断状态:true
* 22:10:01.252 c.Test14 [Thread-0] - 打断状态isInterrupted2:false
* 22:10:01.252 c.Test14 [Thread-0] - 打断状态isInterrupted3:true
*/
}
//本地方法,通过参数ClearInterrupted来控制是否重置中断状态,false就不重置
private native boolean isInterrupted(boolean ClearInterrupted);
public boolean isInterrupted() {
return isInterrupted(false);
}
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
十三、getState() 方法
1、演示代码
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread("t1") {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
log.debug("t1 state: {}", t1.getState());
t1.start();
log.debug("t1 state: {}", t1.getState());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("t1 state: {}", t1.getState());
t1.join();
log.debug("t1 state: {}", t1.getState());
/**
* 运行结果:
* 22:24:31.957 c.Test6 [main] - t1 state: NEW
* 22:24:31.961 c.Test6 [main] - t1 state: RUNNABLE
* 22:24:32.461 c.Test6 [main] - t1 state: TIMED_WAITING
* 22:24:33.964 c.Test6 [main] - t1 state: TERMINATED
*/
}
2、说明
getState() 方法作用是获取线程状态 Java 中线程状态是用 6 个 enum 表示,分别为:NEW, RUNNABLE, BLOCKED, WAITING,TIMED_WAITING, TERMINATED,演示代码演示了4种状态,对于线程的状态后边会单独整理一篇文章。
public State getState() {
// get current thread state
return sun.misc.VM.toThreadState(threadStatus);
}
public static State toThreadState(int var0) {
if ((var0 & 4) != 0) {
return State.RUNNABLE;
} else if ((var0 & 1024) != 0) {
return State.BLOCKED;
} else if ((var0 & 16) != 0) {
return State.WAITING;
} else if ((var0 & 32) != 0) {
return State.TIMED_WAITING;
} else if ((var0 & 2) != 0) {
return State.TERMINATED;
} else {
return (var0 & 1) == 0 ? State.NEW : State.RUNNABLE;
}
}
public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
总结
以上就是对Thread中常用的方法做一个简单讲解,以便学习。在Thread中还有几个已经过时的方法,分别为:
stop() | 停止线程运行 |
suspend() | 挂起(暂停)线程运行 |
resume() | 恢复线程运行 |
这些方法已过时,容易破坏同步代码块,造成线程死锁