✨✨hello,愿意点进来的小伙伴们,你们好呐!
系列专栏:【JavaEE】
本篇内容:带你从0到1了解多线程基槽
作者简介:一名现大二的三非编程小白,日复一日,仍需努力。
1. 程序
》》为了完成特定的任务,用某种语言编写的一组指令的集合,就是我们写的代码就称为程序。
2. 进程
进程就是指在运行中的程序,比如我们使用的某个软件,就启动了一个进程,操作系统就会在内存中给我们分配内存空间,然后又启动另一个软件的话,就又开启了一个进程,操作系统又会为这个进程分配内存空间。进程是程序的一次执行过程,在该过程中存在着产生,存在,消亡。
3.线程
线程就是由进程创建的,是进程的一个体现。一个进程可以同时开启多个线程。
线程可以分为单线程与多线程:
单线程:
在同一个时刻只允许执行一个线程。
多线程:
在同一个深刻,可以执行多个线程,就比如QQ ,可以在同一时刻打开多个聊天框。网易云音乐可以同时下载多曲音乐。
4.并发与并行:
并发:
在同一时刻,多个任务交替执行,一个CPU一直在多个任务之间切换运行,这种就叫做并发,给人一个貌似同时的错觉。单核CPU实现多任务的就是并发。
并发:
在同一时刻,多个任务同时执行。多个CPU执行不同的任务,多核CPU就可以实现并行。
了解了线程的相关概念后,我们来来看看一个线程究竟要怎么来创建吧。
在Java中创建线程有两种方法:1.继承Thread类,2.实现Runnable接口。
我们要编写一个程序来开启一个线程,该线程每隔一秒在控制台输出 “小狗汪汪叫”,当执行到80次就结束该进程。
1.我们编写一个Dog类,该类要继承Thread类。
2. 然后我们在Dog类中要重写run方法。在该方法中编写要进程执行的语句
3.在main方法中创建Dog类的对象,然后调用start方法。
这时候就创建了一个进程·。
那这个时候我们就会有一个疑问了:我们是重写一个run方法,但是为什么创建线程调用的是start方法呢?这时候我们来看看源码中调用start会发生什么事情吧。
public class Test02 {
public static void main(String[] args) {
DOg dog = new DOg();
dog.start();
}
}
class DOg extends Thread {
@Override
public void run() {
for (int i = 0; i < 80; i++) {
System.out.println("小狗汪汪叫~~~~");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3.start0方法底层是由C/C++来编写的,但是调用该方法后,也不一定会执行,只是将线程变为可运行状态,最终运行是通过CPU调用的,取决于CPU。在该方法中再调用我们刚刚重写的run方法。
1. 我们需要在Dog类实现Runnable接口
2. 然后重写run方法,在该方法中编写要执行的代码。
3. 然后在main方法中我们要创建Dog的对象,然后创建Thread对象,将Dog对象传入。
4.最后也是调用start方法。
因为在Threda的构造器中的形参可以传入一个Runnable类型的对象。这就是多态。
为什么调用的是start方法也和继承Thread的方式一样。
public class Test02 {
public static void main(String[] args) {
DOg dog = new DOg();
Thread thread = new Thread(dog);
thread.start();
}
}
class DOg implements Runnable {
@Override
public void run() {
for (int i = 0; i < 80; i++) {
System.out.println("小狗汪汪叫~~~~");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Test02 {
public static void main(String[] args) {
T3 t3 = new T3();
T4 t4 = new T4();
Thread thread1 = new Thread(t3);
Thread thread2 = new Thread(t4);
thread1.start();
thread2.start();
}
}
class T3 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("hello,world");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class T4 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("hi");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
我们来分析一下该程序的线程创建
先创建main主线程,然后在主线程中创建两个子线程。在在main线程销毁的时候子线程也不会销毁
在创建线程本质上来说,继承Thread与实现Runnable接口来创建线程是没有什么区别的。
但是在Java单继承机制中,有时候我们要一个继承了别的类的类来创建进程就需要实现Runnable接口来实现。
实现Runnable接口更加适合多个线程共享一个资源的情况。
线程在哪种情况下会终止呢?
当线程完成任务后,会自动退出。
我们也可以通过控制变量来控制run方法退出。这种方法叫做通知方法,接下来我们来介绍要怎么实现通知方法
我们在run方法中使用while循环,并定义一个boolean变量来充当while循环的条件。
然后在main主线程中调用T3子线程,并让主线程休眠10秒钟,后改变T3中的loop变量,使while循环结束,即控制子线程结束。
这就是通知方法。
public class Test02 {
public static void main(String[] args) throws InterruptedException {
T3 t3 = new T3();
Thread thread = new Thread(t3);
thread.start();
Thread.sleep(10000);
t3.setLoop(false);
}
}
class T3 implements Runnable{
private boolean loop = true;
public boolean getLoop() {
return loop;
}
public void setLoop(boolean loop) {
this.loop = loop;
}
@Override
public void run() {
while(loop){
System.out.println("hello,world");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Test02 {
public static void main(String[] args) throws InterruptedException {
T3 t3 = new T3();
Thread thread = new Thread(t3);
for (int i = 0; i < 20; i++) {
Thread.sleep(1000);
if (i == 10){
Thread.yield();
}
System.out.println("main执行");
}
}
}
class T3 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("hello,world");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Test02 {
public static void main(String[] args) throws InterruptedException {
T3 t3 = new T3();
Thread thread = new Thread(t3);
t3.start();
for (int i = 0; i < 20; i++) {
Thread.sleep(1000);
if (i == 10){
t3.join();
}
System.out.println("main执行");
}
}
}
class T3 extends Thread{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("hello,world");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
这时候子线程插队插入主线程当中。