1. 创建线程的两种方式
- 在java中线程来使用有两种方法。
- 继承Thread类,重写run方法
- 实现Runnable接口,重写run方法
2. 线程应用案例1-- 继承 Thread 类
- 请编写程序,开启一个线程,该线程每隔
1
秒。在控制台输出“瞄瞄,我是小猫咪!”
public class Thread01 {
public static void main(String[] args) {
//创建Cat对象,可以当做线程使用
Cat cat = new Cat();
cat.start();//启动线程
}
}
//说明:
//1.当一个类继承了 Thread 类,该类就可以当做线程使用
//2.我们会重写run方法,写上自己的业务代码
//3. run Thread 类实现了 Runnable 接口的 run 方法
/*
@Override
public void run() {
if (target != null) {
target.run();
}
}
*/
class Cat extends Thread {
int times = 0;
public void run() { //重写run方法,写上自己的业务逻辑
//该线程每隔一秒,在控制台输出“瞄瞄,我是小猫咪!”
while (true) {
System.out.println("喵喵,我是小猫咪!" + (++times));
//让该线程休眠1s , 快捷键:ctrl+alt+t
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
- 无限输出下去
- 对上题改进:当输出
10
次“瞄瞄,我是小猫咪!”,结束该线程
- 当 main 线程启动一个子线程
Thread-0
,主线程不会阻塞,会继续执行,这时主线程和子线程是交替执行的
public class Thread01 {
public static void main(String[] args) throws InterruptedException {
//创建Cat对象,可以当做线程使用
Cat cat = new Cat();
cat.start();//启动线程
//说明:当 main 线程启动一个子线程 Thread-0,主线程不会阻塞,会继续执行
//这时 主线程和子线程是交替执行的
System.out.println("主线程会继续执行" + Thread.currentThread().getName()); //主线程名:main
for (int i = 0; i < 10; i++) {
System.out.println("主线程 i=" + i);
//让主线程休眠
Thread.sleep(1000);
}
}
}
//说明:
//1.当一个类继承了 Thread 类,该类就可以当做线程使用
//2.我们会重写run方法,写上自己的业务代码
//3. run Thread 类实现了 Runnable 接口的 run 方法
/*
@Override
public void run() {
if (target != null) {
target.run();
}
}
*/
class Cat extends Thread {
int times = 0;
public void run() { //重写run方法,写上自己的业务逻辑
//该线程每隔一秒,在控制台输出“瞄瞄,我是小猫咪!”
while (true) {
System.out.println("喵喵,我是小猫咪!" + (++times) + "线程名=" + Thread.currentThread().getName());
//让该线程休眠1s , 快捷键:ctrl+alt+t
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (times == 10) {
break; //当times为10,退出 while 循环,这时线程也就退出了
}
}
}
}
- 使用
JConsole
监控线程执行情况,并画出程序示意图
- 如下,
main
线程 设置执行时间为 60s,子线程Thread-0
执行时间设置为 80s
public class Thread01 {
public static void main(String[] args) throws InterruptedException {
//创建Cat对象,可以当做线程使用
Cat cat = new Cat();
cat.start();//启动线程
//说明:当 main 线程启动一个子线程 Thread-0,主线程不会阻塞,会继续执行
//这时 主线程和子线程是交替执行的
System.out.println("主线程会继续执行" + Thread.currentThread().getName()); //主线程名:main
for (int i = 0; i < 60; i++) {
System.out.println("主线程 i=" + i);
//让主线程休眠
Thread.sleep(1000);
}
}
}
//说明:
//1.当一个类继承了 Thread 类,该类就可以当做线程使用
//2.我们会重写run方法,写上自己的业务代码
//3. run Thread 类实现了 Runnable 接口的 run 方法
/*
@Override
public void run() {
if (target != null) {
target.run();
}
}
*/
class Cat extends Thread {
int times = 0;
public void run() { //重写run方法,写上自己的业务逻辑
//该线程每隔一秒,在控制台输出“瞄瞄,我是小猫咪!”
while (true) {
System.out.println("喵喵,我是小猫咪!" + (++times) + "线程名=" + Thread.currentThread().getName());
//让该线程休眠1s , 快捷键:ctrl+alt+t
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (times == 80) {
break; //当times为80,退出 while 循环,这时线程也就退出了
}
}
}
}
-
可以看出,当时间过了60s后,main线程就会结束,当子线程Thread-0还在继续执行,直到 80s 后才结束线程
-
在多线程编程方面,不是意味着主方法结束了,这个进程就结束了,还要注意子进程的执行时间。主线程结束了,如果还有子线程还在运行,并不会造成应用程序的结束。
2.1 start方法解析
- 为什么启动线程的时候是 start 方法,而不是 run 方法?
//创建Cat对象,可以当做线程使用
Cat cat = new Cat();
cat.start();//启动线程->最终会执行cat的run方法
cat.run();//run就是一个普通的方法,没有真正的启动线程,就会把run方法执行完毕,才会向下执行
- 所以采用的是
start
方法启动线程 - 查看
start
方法的源码:
(1)
public synchronized void start() {
start0();
}
(2)
start0() 是本地方法,是JVM调用, 底层是c/c++实现
真正实现多线程的效果, 是start0(), 而不是 run
private native void start0();