run()方法(只是一个内部方法)
run()方法只是一个类中的普通方法,调用run方法跟调用普通方法一样。
方法 run()称为线程体,它包含了要执行的这个线程的内容,线程就进入了 【运行状态】,开始运行 run 函数当中的代码。
Run 方法运行结束, 此线程终止。再调用start方法报错的。
然后 CPU 再调度其它线程。
启动线程start()方法(开启一个线程)
在 Java中启动多线程调用的是start方法。
在start方法中,真正实现多线程的是一个本地的方法start0。
调用start方法启动一个线程,此时的状态是 就绪。
无需等待run方法体代码执行完毕,可以继续执行下面的代码。
public class TestDemo {
public static void main(String[] args) {
Runnable test = new Runnable() {
public void run() {
String name = Thread.currentThread().getName();
System.out.println("当前运行的线程 : " + name);
}
};
test.run();
// 开启多线程,执行run方法
new Thread(test).start();
}
}
等待一个线程-join()
join()方法是Thread类中的一个方法,该方法的定义是等待该线程终止。其实就是join()方法将挂起调用线程的执行,直到被调用的对象完成它的执行。
现在有两个线程t1和t2,那么如何让t1执行完毕,再去执行t2呢,这里我们就可以用到join()方法,
等待t1执行完毕,再去执行t2线程!!
public class TestDemo {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(){
@Override
public void run() {
for (int i = 0; i < 3; i++) {
try {
System.out.println(this.getName()+"还在运行!");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(this.getName()+"结束了!");
}
};
Thread t2 = new Thread(){
@Override
public void run() {
for (int i = 0; i < 3; i++) {
try {
t1.join();
System.out.println(this.getName()+"还在运行!");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(this.getName()+"结束了!");
}
};
t1.start();
t2.start();
}
}
如果我们,不等待t1线程结束,那么t1线程和t2线程谁会先执行,完全取决于操作系统的调度。也就是并发执行。
public class TestDemo {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(){
@Override
public void run() {
for (int i = 0; i < 3; i++) {
try {
System.out.println(this.getName()+"还在运行!");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(this.getName()+"结束了!");
}
};
Thread t2 = new Thread(){
@Override
public void run() {
for (int i = 0; i < 3; i++) {
try {
//t1.join();
System.out.println(this.getName()+"还在运行!");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(this.getName()+"结束了!");
}
};
t1.start();
t2.start();
}
}
同时join()里也可以设定等待时间,等到这个时间后,就不在等了。
public class TestDemo {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(){
@Override
public void run() {
for(int i = 0 ; i < 10 ; i++){
System.out.println(this.getName()+"在运行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread t2 = new Thread(){
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(this.getName()+"在运行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t1.start();
t1.join(7000);
System.out.println("我不等了");
t2.start();
}
}
中断一个线程,调用 interrupt() 方法来通知
在t1线程运行1m后中断线程。
Thread.currentThread().isInterrupted()内置的一个标记位不用用户自己来创建代码判定。
调用interrupt方法来进行中断时,会遇到2种情况。
a)情况1:如果当线程内部执行的逻辑不涉及到sleep这样的等待,此时就会通过这个标记位来进行退出。
public class TestDemo {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(){
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()){
System.out.println(Thread.currentThread().getName()+" 在运行");
}
}
};
t1.start();
Thread.sleep(1000);
t1.interrupt();
}
}
b)情况2:如果当前线程内部执行的逻辑已经进入sleep了,此时就会触发一个InterruptedException,通过catch捕获到异常,在继续决定如何处理。
这里不做处理,线程就会继续循环才去。
public class TestDemo {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(){
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 在运行");
}
}
};
t1.start();
Thread.sleep(5000);
t1.interrupt();
}
}
此时这里里的break,本质上是让线程的方法能够执行结束~
但是线程是否要结束,还是根据线程自身的方法来决定的~
public class TestDemo {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(){
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//e.printStackTrace();自己打印异常信息
break;
}
System.out.println(Thread.currentThread().getName()+" 在运行");
}
}
};
t1.start();
Thread.sleep(5000);
t1.interrupt();
}
}
currentThread()方法获取当前线程对象的引用
在那个线程中调用,就获取到那个线程对象的引用
如果线程是通过创建Thread子类,并重写run方法来创建的话,此时run方法中,也可以使用this,也能直接找到该线程的引用。
如果是通过Runnable 或者别的方法创建的话,不能用this,只能用Thread.currentThread()。
public class TestDemo {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(){
@Override
public void run() {
System.out.println(this.getId());
}
};
Thread t2 = new Thread(){
@Override
public void run() {
System.out.println(Thread.currentThread().getId());
}
};
t1.start();
t2.start();
System.out.println(Thread.currentThread().getId());
}
}
sleep() 休眠线程
在前几篇博客也使用到了,以及上面的代码也使用到了,他是干什么的呢?
也就是休眠当前线程多少ms后在继续执行线程,但是要抛出 InterruptedException异常。
当前线程进入“休眠状态”即从“运行态”变为“阻塞态”。
在线程休眠结束时,会重新变为“就绪态”等待CPU的调度。
进入休眠状态后,会进入到cpu的等待队列中,直到休眠时间到达,再放回就绪队列,放回就绪队列后,至于啥时候去CPU上运行,就要看调度器是否会立马调度。