【一文通关】Java多线程基础(3)- 常用方法
线程的常用方法
start()方法
start()方法是线程类中用于启动线程的方法。在线程对象创建之后,调用 start() 方法会自动调用线程的 run() 方法(start里面去调用run方法的逻辑是使用C写的),使线程进入可执行状态(从新建状态转化为就绪状态)。线程一旦进入可执行状态,就有可能被CPU调度执行。start() 方法只能被调用一次,多次调用会抛出异常IllegalThreadStateExcellent。
run()方法
在Java中,线程的执行代码通常是通过实现Runnable接口来完成的。Runnable接口中有一个run()方法,该方法定义了线程要执行的代码。当一个线程被创建并启动后,它的run()方法会被自动调用。当run()方法被执行完毕,线程会变为死亡状态。
所以要再调用start()方法,需要等run()方法执行完毕,否则会抛出异常IllegalThreadStateExcellent
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("MyRunnable is running...");
}
}
public class Main {
public static void main(String[] args) {
// 创建线程对象
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
// 启动线程
thread.start();
}
}
在本例中,我们定义了一个实现了Runnable接口的MyRunnable类,并覆写了run()方法。在主线程中,我们创建了一个MyRunnable对象myRunnable,并将其作为参数传递给Thread构造函数,创建一个Thread对象thread。最后,我们调用thread的start()方法启动线程。这将导致线程进入可执行状态,并自动调用run()方法。在本例中,线程的执行结果将在控制台上打印一条消息"MyRunnable is running..."。
需要注意的是,Java中的线程可以通过继承Thread类来创建,但这种方式并不推荐,因为继承Thread类会限制代码的灵活性,而实现Runnable接口则可以更好地实现代码的复用。
sleep(int millsecond)
线程的执行是按照优先级来进行的, 当高级别的线程未死亡时,低级别的线程是不可能获得CPU资源的。
但有时我们需要低级别的线程先做一些工作来配合高级别的线程,因此,需要高级别的线程让出CPU资源, 此时,我们就可以使用sleep()方法, 让它休眠一会儿。
休眠的时间由你的参数决定, millsecond是以毫秒为单位的休眠时间。如果线程在休眠时被打断,JVM就抛出InterruptedException
, 所以,sleep方法必须在try-catch语句中。
isAlive()
线程处于新建状态,即分配了空间,但没有调用start()之前, isAlive()
返回false;
线程调用了start()
方法并且占用了CPU的资源, 将调用run()
方法,在run()
方法结束之前,线程调用isAlive()
返回true。
当线程处于死亡状态,即run()
方法执行完毕,这时isAlive()
方法返回false。
常见问题
一个正在运行的线程在死亡状态之前, 是不能再给它分配实体的。 原因: 线程只能引用最后分配的实体,之前的实体就会成为垃圾, 并且不会被垃圾收集器收集。
Thread thread = new Thread(target);
thread.start();
这时候如果再次分配实体
thread = new Thread(target)
那么,先前的实体就会成为垃圾, JVM认为它是一个垃圾, 但是不敢将其回收, 原因: 如果垃圾正在运行,突然释放可能会引起错误或者设备毁坏。
currentThread()
currentThread()方法是Thread类中的类方法, 可以使用类名调用,该方法返回当前正在使用CPU资源的线程
interrupt方法
当一个线程调用interrupt()方法时,该线程的中断标志位将被设置为true,但并不会立即停止线程的执行。在线程执行代码中,可以通过检查中断标志位来判断线程是否被中断,并根据需要进行相应的处理。
当一个线程处于阻塞状态时(如等待、睡眠或者等待锁),如果它的中断标志位被设置为true,则该线程将抛出一个InterruptedException异常,从而提前结束阻塞状态,回到可执行状态。但是,如果线程没有处于阻塞状态,那么设置中断标志位将不会产生任何效果,线程仍然会继续执行。
举一个例子:
有三个线程, 小明,小红和老师,他们都在一个教室里, 小明正在睡觉,而小红一直在处于听课状态;当老师叫上课后,小明被惊醒。
具体代码如下:
public class Main {
public static void main(String[] args) throws InterruptedException {
Classroom room = new Classroom();
room.ming.start();
room.hong.start();
room.teacher.start();
}
}
class Classroom implements Runnable{
Thread ming, hong, teacher;
Classroom(){
this.ming = new Thread(this);
this.hong = new Thread(this);
this.teacher = new Thread(this);
ming.setName("小明");
hong.setName("小红");
}
@Override
public void run() {
Thread thread = Thread.currentThread();
if(thread == ming){
System.out.println("老子在睡觉");
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
System.out.println("我被吵醒了");
}
System.out.println("假装听课");
} else if (thread == hong) {
System.out.println("我一直在听课");
// while (!hong.isInterrupted()){
// System.out.println("我还没被打断");
// }
// System.out.println("被打断了");
} else if (thread == teacher) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("上课了");
ming.interrupt();
System.out.println("hong前的interrupted值:" + hong.isInterrupted());
hong.interrupt();
System.out.println("hong后的interrupted值:" + hong.isInterrupted());
}
}
}
输出: 老子在睡觉 我一直在听课 上课了 我被吵醒了 假装听课 hong前的interrupted值:false hong后的interrupted值:true
可以看出, 当处于sleep状态时,调用interrupt()方法会抛出InterruptedException。
当不处于阻塞状态时,对其调用interrupt方法只会改变它里面的interrupted属性的值。
转载自:https://juejin.cn/post/7228022437702352956