线程的介绍

简介

  • 程序:是为了完成特定的任务,用某种语言编写的一组指令的集合。
  • 进程就是指运行中的程序,进程是程序的一次执行过程,或者是正在运行的一个程序。是一个动态的过程,有他自身的产生,存在和消亡。
  • 线程是进程创建的,是进程的一个实体,一个进程可以拥有多个线程。
  • 单线程同一个时刻只允许执行一个线程
  • 多线程,同一个时刻,可以执行多个线程
  • 并发:同一个时刻,多个任务交替执行,造成一个“貌似同时”的错觉,简单来说,单核cpu实现多任务就是并发。
  • 并行:同一个时刻,多个任务同时执行,多核cpu可以实现并行。并发和并行可以同时存在,如果任务过多。

创建线程的两种方法

继承Thread类,重写run方法

练习1

每隔一秒输出一个语句,20秒结束

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* @author zss
*/

public class Test {
public static void main(String[] args) {
Cat cat = new Cat();
cat.start();
}
}
/**当一个类继承了Thread类,该类就可以当作线程使用,run方法来源于Runnable接口*/
class Cat extends Thread{
int time=0;
@Override
public void run(){
while (true){
System.out.println("喵喵,我是小喵咪");
time++;
try{
Thread.sleep(1000);}catch (Exception e){
System.out.println("发生了错误");
}
if (time==20){
break;
}
}
}
}

image-20220316170923325

通过实现Runnable接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* @author zss
*/

public class Test {
public static void main(String[] args) {
Cat cat = new Cat();
//不可调用
//cat.run();
Thread thread = new Thread(cat);
thread.start();
}
}

/**当一个类继承了Thread类,该类就可以当作线程使用,run方法来源于Runnable接口*/
class Cat implements Runnable{
@Override
public void run() {
while (true){
System.out.println("喵喵");
}
}
}

image-20220317110132194

其实我们的底层使用了静态代理模式,而之所以可以使用Thread方法传入cat,是因为构造函数中存在Thread(Runnable),而Cat继承了Runnable。

1
2
Thread thread = new Thread(cat);
thread.start();

image-20220317111254838

模拟线程代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class ThreadProxy implements Runnable{
private Runnable target=null;
@Override
public void run() {
if (target!=null){
//动态绑定机制到我们新定义的run
target.run();
}
}
//源码中含有一个构造函数
public ThreadProxy(Runnable target) {
this.target = target;
}
public void start(){
start0();
}
public void start0(){
run();
}
}

总结

其实总源码上来看,这两个创建线程的机制没有本质的区别,他们的底层都是调用start0机制进行线程的创建,而且Thread其实是调用了Runnable接口的。

但是Runnable接口更加适合多个线程共享一个资源的情况(可以将两个线程同时调用cat对象),并且避免了单继承的限制。