0 Java线程运行说明
0.1 线程运行过程
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println("thread");
});
thread.start();
System.out.println("main");
}
说明: 我们知道,java在启动的时候,已经自动创建了主线程,主线程调用main方法,main方法中又创建了一个线程(命名为”thread线程“),这个线程的任务是打印”thread“,同时,main方法中在创建一个新线程后的任务是打印”main“。当创建了thread线程并且start后,主线程和thread线程就是广泛上定义的并发(并发+并行)的过程,这个时候先打印”main“还是先打印”thread“是不确定的,是随机的,要看操作系统的随机调度。 同样着,谁先结束也是不确定的,也可能是主线程先结束,也可能是thread线程先结束。所以,为了让主线程等待thread线程结束,需要使用join方法。
0.2 线程运行过程
0.3 Thread构造器:
0.4 Thread常用方法和属性(以下都是获取到的一瞬间的状态,不是持续的状态。)
-
Thread.getID: ID表示线程的身份。ID有好几个,这里的方法获取到的是线程在JVM中的身份标识。线程的标识有好几个,在内核的PCB上有标识,在用户态线程库中也有标识(操作系统系统的线程库).
-
Thread.getName(): getName()方法是获取到在Thread构造方法中传入的名字。
-
Thread.getStatus() getState()方法是一个比较关键的属性。在PCB里面有几个状态,在这里得到的状态是JVM设定的状态,比操作系统内置的状态更加丰富。
-
Thread.isDaemon() : daemon称为”守护线程“,也可以称为后台线程。比如手机上的app,打开app,这个app就来到前台,当我们切换应用的时候,这个app就到后台了。线程也分成前台线程和后台线程,也可以设置线程的前后台。【一个线程创建出现默认是前台线程,前台线程会阻止进程的退出,进程会保证所有的前台线程都执行结束,才会退出。对于后台线程,不会阻止进程的结束,进程退出的时候,不管线程是否执行结束。main线程是一个前台线程。】
-
Thread.isAlive() : 判断线程是否存活状态。
-
Thread.isInterupted(): 想让线程结束,只要让线程的入口方法执行结束,线程就随之结束了。线程的入口方法,对于主线程来说,main方法就是它的入口方法;对于其他线程来说,run()方法中要执行的任务或者Runnable,lambda中的内容就是它的入口方法。 isInterrupted()方法是一个判定内置的标志位,默认是false,true表示线程要中断。现在运行,查看结果。调用interrupt,产生异常,但是线程还是在继续运行。
-
中断线程两种方法:
-
- 直接手动创建标志位来区分线程是否要结束;
//boolean表示线程标志位
private static boolean isQuit = false;
public static void main(String[] args) {
Thread thread = new Thread(() -> {
while (!isQuit) {
System.out.println("线程运行中...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("新线程执行结束");
});
thread.start();
try {
Thread.sleep(5000);
System.out.println("控制新线程退出");
isQuit = true;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
能控制线程结束,主要是这个线程有一个循环,这个循环执行结束,就算结束了这个线程。这样的情况是非常常见的,很多时候创建线程都让线程完成一些比较复杂的任务,往往都有一些循环。如果线程本身执行很快,一下子就结束了,也就没有提前控制的必要了。
-
- Thread内置的标志位
- Thread.currentThread() 方法 是一个静态的方法,通过这个方法获取当前线程的实例(Thread对象),这个方法总会有一个线程会调用它。哪一个线程调用这个方法,就返回哪一个线程的Thread对象。
1 Java多线程的4种创建方式
1.1 继承Thread类创建多线程
步骤:
- 继承Thread类,创建一个新的线程类;
- 重写run()方法,将需要并发执行的业务代码编写在run()方法中;
- 调用线程的start()方法启动线程。
public class Thread1Test {
public static String getCurrentThread() {
return Thread.currentThread().getName();
}
static class CreateThread extends Thread {
@Override
public void run() {
System.out.println("线程名称为:" + getCurrentThread() + "启动运行····");
System.out.println("running-----");
System.out.println("over!");
}
}
public static void main(String[] args) {
Thread thread = null;
for (int i = 0; i < 5; i++) {
thread = new CreateThread();
thread.start();
}
System.out.println("线程名称为:" + getCurrentThread() + "运行结束");
}
}
1.2 实现Runnable接口创建多线程
步骤如下:
- 创建实现Runnable接口 的类,比如:RunnableThread 类。重写run()方法, 将并发代码写入其中;
- 调用。 创建Runnable runnable = new RunnableThread(); 多态方式,创建接口的实现类, 创建Thread对象,将runnable作为参数让Thread 引用执行。
- 调用线程的start()方法启动线程。
public class RunnableTest {
public static String getCurrentThread() {
return Thread.currentThread().getName();
}
static class CreateThread implements Runnable {
@Override
public void run() {
System.out.println("线程名称为:" + getCurrentThread() + "启动运行····");
System.out.println("running-----");
System.out.println("over!");
}
}
public static void main(String[] args) {
Thread thread = null;
for (int i = 0; i < 5; i++) {
Runnable runnable = new CreateThread();