常用方法
方法名 | static | 功能说明 | 注意 |
---|---|---|---|
start() | 启动一个新线 程,在新的线程运行 run 方法中的代码 | start() 方法只是让线程进入就绪,里面代码不一定立刻运行(CPU 的时间片还没分给它)。每个线程对象的 start方法只能调用一次,如果调用了多次会出现 IllegalThreadStateException | |
run() | 新线程启动后,内部调用的方法 | 如果在构造 Thread 对象时传递了 Runnable 参数,则线程启动后会调用 Runnable 中的 run 方法,否则默认不执行任何操作。但可以创建 Thread 的子类对象, 来覆盖默认行为 | |
join() | 等待线程运行结束 | ||
join(long n) | 等待线程运行结 束,最多等待 n 毫秒 | ||
getId() | 获取线程长整型的 id | id 唯一 | |
getName() | 获取线程名 | ||
setName(String) | 修改线程名 | ||
getPriority() | 获取线程优先级 | ||
setPriority(int) | 修改线程优先级 | java中规定线程优先级是1~10 的整数,较大的优先级 能提高该线程被 CPU 调度的机率 | |
getState() | 获取线程状态 | Java 中线程状态是用 6 个 enum 表示,分别为: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED | |
isInterrupted() | 判断是否被打断 | 不会清除打断标记 | |
isAlive() | 线程是否存活(还没有运行完 毕) | ||
interrupt() | 打断线程 | 如果被打断线程正在 sleep、wait、join,会导致被打断的线程抛出 InterruptedException,同时打断标记会被清除; 如果打断的是正在运行的线程,则会设置打断标记; park 的线程被打断,也会设置打断标记 |
|
interrupted() | static | 判断当前线程是否被打断 | 会清除打断标记 |
currentThread() | static | 获取当前正在执行的线程 | |
sleep(long n) | static | 让当前执行的线 程休眠n毫秒, 休眠时让出 cpu 的时间片给其它 线程 | |
yield() | static | 提示线程调度器 让出当前线程对 CPU的使用 | 主要是为了测试和调试 |
演示
start
启动线程的方法,不做演示了,嘻嘻
run
run 方法是线程启动后,内部执行的方法,一般不要主动调用合格方法。
如果在程序中主动调用了这个方法,则现成的任务就会在调用者所在的线程内执行。
public static void main(String[] args) {
Thread t1 = new Thread("t1") {
@Override
public void run() {
log.debug("任务执行");
}
};
t1.run();
log.debug("do other things ...");
}
sleep
顾名思义,就是睡眠,调用 Thread.sleep() 会让当前线程从 Running 进入 Timed Waiting 状态(阻塞),睡眠结束线程恢复执行(但是不一定会立刻执行)。
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
log.debug("我睡了");
try {
Thread.sleep(TimeUnit.SECONDS.toMillis(5));
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("睡饱了");
}, "t1");
t1.start();
}
其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出 InterruptedException,打断标记会被清除。
yield
参看这篇文章:https://blog.csdn.net/dabing69221/article/details/17426953
调用 yield 会让当前线程从 Running 进入 Runnable 状态,即让出 cpu 的使用权, 与其他同样是 Runnable 状态的线程一齐竞争 cpu 的使用权。
public class YieldTest extends Thread {
public YieldTest(String name) {
super(name);
}
@Override
public void run() {
for (int i = 1; i <= 50; i++) {
System.out.println("" + this.getName() + "-----" + i);
// 当i为30时,该线程就会把CPU时间让掉,让其他或者自己的线程执行(也就是谁先抢到谁执行)
if (i == 30) {
this.yield();
}
}
}
public static void main(String[] args) {
YieldTest yt1 = new YieldTest("张三");
YieldTest yt2 = new YieldTest("李四");
yt1.start();
yt2.start();
}
}
运行结果:
第一种情况:李四线程当执行到30时,会让掉CPU时间片,这时张三(线程)抢到CPU时间并执行。
第二种情况:李四(线程)当执行到30时,会让掉CPU时间片,这时李四(线程)抢到CPU时间并执行。
join
用于等待线程的结束,通常用在主线程等待其他线程的计算完成,主线程再运行。
无超时等待,就嗯等:
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
log.debug("线程1开始");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
a += 10;
log.debug("线程2结束");
});
t1.start();
// main线程等待 t1 运行结束
t1.join();
log.debug("主线程拿到的a是:{}", a);
}
有超时等待,等不到就算了:
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
log.debug("线程1开始");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
a += 10;
log.debug("线程2结束");
});
t1.start();
// main线程等待 t1 运行结束,单位是ms
t1.join(1000);
log.debug("主线程拿到的a是:{}", a);
}
interrupt
虽然 interrupt 有打断的意思,但是执行了 interrupt() 线程依然会继续执行,我们重点关注的是线程的打断标记,未被打断是 true,被打断了是 false,根据这个打断标记,我们可以做出对应的逻辑。
打断正常运行的线程
打断标记会置为 true
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
log.debug("线程开始");
while (true) {
Thread current = Thread.currentThread();
boolean interrupted = current.isInterrupted();
if (interrupted) {
log.debug(" 打断状态: {}", interrupted);
break;
}
}
log.debug("线程结束");
}, "t1");
t1.start();
Thread.sleep(500);
t1.interrupt();
}
打断 sleep,wait,join 的线程
打断执行了或正在执行以上方法的线程,会导致被打断的线程抛出 InterruptedException,并且这些线程会进入阻塞状态 ,同时打断标记会被清除(置为false)。
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
log.debug("线程开始");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("线程结束");
}, "t1");
t1.start();
Thread.sleep(200);
t1.interrupt();
log.debug(" 打断状态: {}", t1.isInterrupted());
}
打断 park 的线程
打断 park 线程,不会清除打断标记
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
log.debug("park...");
LockSupport.park();
log.debug("unpark...");
log.debug("打断状态:{}", Thread.currentThread().isInterrupted());
}, "t1");
t1.start();
Thread.sleep(500);
t1.interrupt();
}
park、unpark
注意,这两个方法并不是 Thread 类的方法,而是 LockSupport 类中的方法,park 用于暂停当前线程,unpark 用于恢复指定线程。
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
log.debug("start...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("park...");
LockSupport.park();
log.debug("resume...");
},"t1");
t1.start();
Thread.sleep(2000);
log.debug("unpark...");
LockSupport.unpark(t1);
}
如果执行 park 前,打断标记已经是 true,那么 park 将会失效
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
// 1~4的循环时,park会失效
for (int i = 0; i < 5; i++) {
log.debug("park {}...", i);
LockSupport.park();
log.debug("打断状态:{}", Thread.currentThread().isInterrupted());
}
}, "t1");
t1.start();
Thread.sleep(1000);
t1.interrupt();
}
不推荐使用的方法
这些方法已过时,使用起来很容易破坏同步代码块,造成线程死锁
方法名 | static | 功能说明 |
---|---|---|
stop() | 停止线程运行 | |
suspend() | 挂起(暂停)线程运行 | |
resume() | 恢复线程运行 |