体验多线程抢占 CPU 资源的测试
主线程在调用时与多线程互不影响,代码如下所示:
public class test0 {
public static void main(String[] args) {
System.out.println("hello world");
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
System.out.println("hello world");
}
}
class MyRunnable implements Runnable{
@Override
public void run(){
System.out.println("hello myRunnable" + Thread.currentThread().getName());
}
}
按正常逻辑来讲,此时应该先输出 2 个 hello world,再输出 hello myRunnable,但由于我们调用的是多线程,所以输出结果如下所示:
此时线程是相对混乱的,由 CPU 自行进行分配,所以不要在意此时的执行顺序,但是从此处可以看出,java 主线程与多线程之间的区别。
start() 和 run() 之间的区别
start()
start() 函数 API 定义:
使该线程开始执行,Java 虚拟机调用该线程的 run 方法。结果是两个线程并发地运行;当前线程(从调用返回给 start 方法)和另一个线程(执行其 run 方法)。多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。
start() 函数启动线程执行以下任务:
- 它统计了一个新线程
- 线程从 New State 移动到 Runnable 状态。
- 当线程有机会执行时,它的目标 run() 方法将运行。
- start() 方法不能多次重复调用,否则抛出 java.lang.IllegalStateException 异常;
小结:
start() 函数用来启动线程,真正实现了多线程运行。这时无需等待 run 方法体代码执行完毕,可以直接继续执行下面的代码;通过调用 Thread 类的 start() 方法来启动一个线程, 这时此线程是处于就绪状态, 并没有运行。 然后通过此 Thread 类调用方法 run() 来完成其运行操作的, 这里方法 run() 称为线程体,它包含了要执行的这个线程的内容。 Run 方法运行结束, 此线程终止。然后 CPU 再调度其它线程。
run()
run() 函数 API 定义:
如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。Thread 的子类应该重写该方法。
run() 函数启动:
线程类的 run() 方法是 Runnable 接口的一个抽象函数,由 java 虚拟机直接调用的,不会创建的新线程。所以可以被多次调用,因为它只是一个抽象函数。
小结:
run() 函数只是类的一个普通函数而已,如果直接调用 run 方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待 run 方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。
IllegalComponentStateException 异常
IllegalComponentStateException 异常概念
IllegalComponentStateException 异常是 RuntimeException 异常的父类,指无效状态异常,在不合理或不正确时间内唤醒一方法时出现的异常信息。换句话说,即 Java 环境或 Java 应用不满足请求操作。
多线程就是分时利用 CPU,宏观上让所有线程一起执行 ,也叫并发。在真正工作及学习使用中,想要异步的情况下需尽可能使用 start() 函数。但是 start() 方法不能多次重复调用,否则抛出 java.lang.IllegalStateException 异常;
重复调用 start() 报出 IllegalComponentStateException 异常
在 project 中创建 test2.java 文件
public class test2{
public static void main(String[] args){
Thread MyThread = new MyThread();
for(int i = 0; i < 2; i++){
MyThread.start();
}
}
}
class MyThread extends Thread{
@Override
public void run(){
System.out.println("hello myThread" + Thread.currentThread().getName());
}
}
public class test2{ public static void main(String[] args){ Thread MyThread = new MyThread(); for(int i = 0; i < 2; i++){ MyThread.start(); } } } class MyThread extends Thread{ @Override public void run(){ System.out.println(“hello myThread” + Thread.currentThread().getName()); } }
打开 terminal,输入命令编译并运行:
javac test2.java java test2
运行结果将会抛出 IllegalComponentStateException 异常,如下所示:
非重复调用 start() 不会报出异常
在 project 中创建 test3.java 文件
public class test3{
public static void main(String[] args){
for(int i = 0; i < 2; i++){
Thread MyThread = new MyThread();
MyThread.start();
}
}
}
class MyThread extends Thread{
@Override
public void run(){
System.out.println("hello myThread" + Thread.currentThread().getName());
}
}
public class test3{ public static void main(String[] args){ for(int i = 0; i < 2; i++){ Thread MyThread = new MyThread(); MyThread.start(); } } } class MyThread extends Thread{ @Override public void run(){ System.out.println(“hello myThread” + Thread.currentThread().getName()); } }
打开 terminal,输入命令编译并运行:
javac test3.java java test3
由于该实例每次都重新创建 MyThread 线程,而非在一个线程中频繁调用start()函数,所以运行结果将执行 2 次 Hello MyThread();
重复调用 .run() 不会报出异常
在 project 中创建 test4.java 文件
public class test4{
public static void main(String[] args){
Thread MyThread = new MyThread();
for(int i = 0; i < 2; i++){
MyThread.run();
}
}
}
class MyThread extends Thread{
@Override
public void run(){
System.out.println("hello myThread" + Thread.currentThread().getName());
}
}
public class test4{ public static void main(String[] args){ Thread MyThread = new MyThread(); for(int i = 0; i < 2; i++){ MyThread.run(); } } } class MyThread extends Thread{ @Override public void run(){ System.out.println(“hello myThread” + Thread.currentThread().getName()); } }
打开 terminal,输入命令编译并运行:
javac test4.java java test4
运行结果如下所示
此时便证明了,run() 函数只是一个普通的函数,而start() 函数才是真正意义上的创建了多线程。