线程P2 | Thread类的基本用法
通过上述创建过程,我们可以发现,要实现线程的创建和运行,需要start()方法和run()方法的共同协作,那么也许大家会有疑问,这两个方法到底有什么区别呢,可以混用吗?但是要注意的是,此处结果肯定不一定是2000,因为创建线程,启动main等等之类的行为也是需要时间的,所以我们只是保证一定会 >= 2000就说明确实是有休眠存在的~~有的时候,我们有的线程需要等待其它线程做完工作之后,才开始被执行
创建线程
创建线程我们要通过Thread类来实现,一共有下述5种创建方式
继承 Thread, 重写 run
//先创建一个自己的Thread类,继承自Thread类
class MyThread extends Thread {
//这里重写run()方法
@Override
public void run() {
while (true) {
System.out.println("Hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
Thread t = new MyThread();
t.start(); //记得在main里面启动线程喔
while (true) {
System.out.println("Hello main");
Thread.sleep(1000);
}
}
}
结果如下所示
以下几种创建方式将不再展示结果,因为结果相同,只是创建的方式不同~~
实现 Runnable, 重写 run
//创建自己的Thread类,接入Runnable接口
class MyRunnable implements Runnable {
//重写run()方法
@Override
public void run() {
while (true) {
System.out.println("Hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Demo2 {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new MyRunnable());
t.start();
while (true) {
System.out.println("Hello main");
Thread.sleep(1000);
}
}
}
继承 Thread, 重写 run, 使用匿名内部类
public class Demo3 {
public static void main(String[] args) throws InterruptedException {
//直接在创建时使用匿名内部类
Thread t = new Thread() {
//还是要重写run()方法
@Override
public void run() {
while (true) {
System.out.println("Hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t.start();
while (true) {
System.out.println("Hello main");
Thread.sleep(1000);
}
}
}
实现 Runnable, 重写 run, 使用匿名内部类
public class Demo4 {
public static void main(String[] args) throws InterruptedException {
//创建时用Runnable的匿名内部类
Thread t = new Thread(new Runnable() {
//还是要重写run()方法
@Override
public void run() {
while (true) {
System.out.println("Hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
t.start();
while (true) {
System.out.println("Hello main");
Thread.sleep(1000);
}
}
}
使用 lambda 表达式
最推荐的方式,并且不用重写run()方法
public class Demo5 {
public static void main(String[] args) throws InterruptedException {
//使用lambda表达式,不用重写run()方法
Thread t = new Thread(() -> {
while (true) {
System.out.println("Hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
while (true) {
System.out.println("Hello main");
Thread.sleep(1000);
}
}
}
启动线程:start()方法和run()方法的区别
通过上述创建过程,我们可以发现,要实现线程的创建和运行,需要start()方法和run()方法的共同协作,那么也许大家会有疑问,这两个方法到底有什么区别呢,可以混用吗?
所以在这里,我们简单地为大家介绍一下
从方法性质上说
- 从方法性质上来说,我们在创建过程中可以发现,run()方法是在普通方法,需要被重写使用;run()方法是会在线程启动时被直接调用的,是被动被执行的
- start()方法则是Thread类中特有的方法,调用这个方法是主动执行的
从结果上来说
- 如果直接执行run()方法就和执行一个普通方法一样,是按顺序执行的,并不能启动一个新的线程
- 如果执行start()方法,就是启动一个新的线程~~运行过程是会和main()方法并发执行的多线程
大家在使用的时候一定不要用错了!!~~
中断线程
这里我们讨论的主要是如何去中断线程,一般有以下两种情况
通过共享的标记来沟通
场景提示
我们在用代码展示之前,先设置一个场景,假设你受老板之托帮助公司转账,但是后面老板发现,对面好像是个骗子,于是你和老板约定好了一个变量 isQuit[可以看作是手机],如果老板发现对面是骗子,那么就会把这个变量变成true,然后告诉你,你收到消息也马上停止转账;反之,如果是false,你就继续转账
public class Demo12 {
public static volatile boolean isQuit = false;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
System.out.println("你正在转账");
while (!isQuit) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("你停止了转账");
});
System.out.println("老板喊你开始转账");
t1.start();
Thread.sleep(2000);
System.out.println("老板发现对方是骗子,打电话通知你");
isQuit = true; //这里置为true可以理解为老板打电话的过程
}
}
使用interrupt()方法来通知
同样的场景,我们用interrupt()来实现
public class Demo13 {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
System.out.println("你正在转账");
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
System.out.println("你停止了转账");
});
System.out.println("老板喊你开始转账");
t1.start();
Thread.sleep(4000);
System.out.println("老板发现对方是骗子,打电话通知你");
t1.interrupt(); //用interrupt()方法实现打电话
}
}
等待线程
有的时候,我们有的线程需要等待其它线程做完工作之后,才开始被执行,这个时候,我们称它需要等待其它线程,而要实现这样的功能,就需要用到join()方法,老规矩,我们还是上情景~~
场景
Tina觉得最近太热了,想开空调,发现没电费了,于是Tina要先充电费才能开空调,即开空调这个线程应该等待充电费这个线程
public class Demo14 {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
try {
Thread.sleep(2000);
System.out.println("充值电费");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("电费充值完毕");
});
Thread t2 = new Thread(() -> {
try {
Thread.sleep(2000);
System.out.println("打开空调");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("空调已开启~~Tina感觉很凉快 :) ");
});
System.out.println("Tina想开空调,发现没电了!!");
Thread.sleep(3000);
System.out.println("Tina先充了电费");
t1.start();
t1.join(); //空调要等电费充完才能打开
Thread.sleep(2000);
System.out.println("太好了!!电费充好了~~Tina打开了空调");
t2.start();
}
}
休眠线程
其实关于线程的休眠,我们前面已经多次使用过了,就是Thread.sleep()方法,单位是毫秒,使用之后,线程就会进入休眠状态,值得注意的是,它的使用必须要处理异常~~
public class Demo15 {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
long startTime = System.currentTimeMillis();
try {
Thread.sleep(2000);
long endTime = System.currentTimeMillis();
System.out.println("休眠时间:" + (endTime - startTime));
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
}
}
我们可以搞个计时器来记录一下休眠的情况
但是要注意的是,此处结果肯定不一定是2000,因为创建线程,启动main等等之类的行为也是需要时间的,所以我们只是保证一定会 >= 2000就说明确实是有休眠存在的~~
更多推荐
所有评论(0)