线程使用
大约 3 分钟
线程使用
创建线程的两种方式
- 继承 Thread 类,重写 run方法
- 实现 Runnable 接口,重写 run 方法
示例1 - 继承 Thread 类
- 请编写程序,开启一个线程, 该线程每隔1秒。在控制台输出 “喵喵, 我是小猫咪”
- 对上题改进:当输出 80 次 喵喵, 我是小猫咪,结束该线程
- 使用 JConsole 监控线程执行情况,并画出程序示意图!
package commonThread;
public class Thread01 {
public static void main(String[] args) throws InterruptedException {
// 创建 Cart 对象,可以当做线程使用
Cart cart = new Cart();
cart.start(); // 启动线程->最终会执行cat的run方法
// cart.run(); //run方法就是一个普通的方法,没有真正的启动一个线程,就会把run方法执行完毕,才向下执行
/**
* 说明
* 当main线程启动一个子线程 Thread-0,主线程不会阻塞,会继续执行
*/
System.out.println("主线程继续执行" + Thread.currentThread().getName());
for (int i = 0; i < 800; i++){
System.out.println("主线程 i = " + i);
Thread.sleep(1000);
}
}
}
/**
* 1. 当一个类继承了 Thread 类,该类就可以当做线程使用
* 2. 我们会重写 run 方法,写上自己的业务代码
* 3. Thread 类本身没有 run 方法 是 Thread 类 实现了 Runnable 接口的 run 方法
*/
class Cart extends Thread { // 重写 run 方法,写上自己的业务逻辑
int times = 0;
@Override
public void run() {
while (true) {
// 该线程每隔1秒。在控制台输出“喵喵,我是小猫咪”
System.out.println("喵喵,我是小猫咪" + (++times) + " 线程名:" + Thread.currentThread().getName());
try {
// 让该线程休眠1秒 快捷键 ctrl + alt + t
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(times == 800) {
break;
}
}
}
}
打开终端,输入JConsole,回车,找到对应的线程名
示意图

示例2 - 实现 Runnable 接口
说明
- java 是单继承的,在某些情况下一个类可能已经继承了某个父类,这时在用继承Thread类方法来创建线程显然不可能了。
- java 设计者们提供了另外一个方式创建线程,就是通过实现 Runnable 接口来创建线程
package commonThread;
public class Thread02 {
public static void main(String[] args) {
Dog dog = new Dog();
// dog.start(); 这里不能调用 start
// 创建 Thread 对象,把 dog 对象(实现Runnable) 放入 Thread
Thread thread = new Thread(dog); // 这里底层使用了设计模式[代理模式]
thread.start();
}
}
class Dog implements Runnable {
int count = 0;
@Override
public void run(){
try {
while (true) {
System.out.println("小狗" + (++count) + Thread.currentThread().getName());
Thread.sleep(1000);
if(count == 80) {
break;
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
案例3 - 多线程执行
请编写一个程序,创建两个线程,一个线程每隔 1秒 输出 “hello,world”,输出 10次,退出,一个线程每隔 1秒 输出 “hi” ,输出 5次退出
package commonThread;
public class Thread03 {
public static void main(String[] args) {
Dog1 dog1 = new Dog1();
Dog1 dog2 = new Dog1();
Thread thread1 = new Thread(dog1);
Thread thread2 = new Thread(dog2);
thread1.start();
thread2.start();
}
}
class Dog1 implements Runnable {
int count = 0;
@Override
public void run(){
while(true) {
try {
System.out.println("Dog1 线程" + (++count) + Thread.currentThread().getName());
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
class Dog2 implements Runnable {
int count = 0;
@Override
public void run(){
while(true) {
try {
System.out.println("Dog2 线程" + (++count) + Thread.currentThread().getName());
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
继承 Thread VS 实现 Rlnnable 的区别
- 从 Java 的设计来看,通过继承 Thread 或者实现 Runnable 接口来创建线程本质上没有区别,从 Jdk 帮助文档我们可以看到 Thread 类本身就实现了 Runnable 接口 start() ---> start0()
- 实现 Runnable 接口方式更加适合多个线程共享一个资源的情况,并且避免了单继承的限制
线程终止
说明
- 当线程完成任务后,会自动退出
- 还可以通过使用变量来控制 run 方法退出的方式停止线程,即通知方式
示例
需求: 启动一个线程 t,要求在 main 线程中去停止线程 t, 请编程实现,
package commonThread;
public class Thread04 {
public static void main(String[] args) throws InterruptedException {
T t = new T();
Thread thread = new Thread(t);
thread.start();
Thread.sleep(2000);
t.setLoop(false);
}
}
class T extends Thread {
int count = 0;
private boolean loop = true;
@Override
public void run() {
while(loop) {
System.out.println("主线程" + (++count));
}
}
public void setLoop(boolean loop) {
this.loop = loop;
}
}