从现在开始,我们进入并发编程的学习,那么首先我们要了解的就是多线程。

Java单线程程序已经能够完成逻辑处理,为什么还需要“多线程”呢?

单线程只能同时做一件事,无法同时进行多个任务。如果某个操作耗时较长,会引起主线程的阻塞,导致程序变慢。

单线程像是你在同一时间只能写作业,而有些人却能够边听歌,看综艺,还能写作业。

进程与线程?

在操作系统中,我们常听到“进程”和“线程”这两个词,它们到底是什么?两者有什么区别?为什么需要多线程而不是直接使用多个进程?

概念 定义
进程 操作系统资源分配的基本单位。每个运行中的程序就是一个进程,拥有独立的内存空间和系统资源。
线程 进程中执行的最小单元,是CPU调度的基本单位。一个进程中可以包含多个线程,它们共享进程的资源。

简单来说,每个程序就是一个进程,一个进程可以拥有多个线程

Java 中创建多线程的常见方式

继承Thread类

1
2
3
4
5
6
7
8
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Hello from MyThread!");
}
}

new MyThread().start(); // 启动线程

实现Runnable接口

1
2
3
4
5
6
7
8
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Hello from Runnable!");
}
}

new Thread(new MyRunnable()).start(); // 启动线程

实现 Runnable 更加灵活、解耦性好,是更推荐的做法。
从上述内容看到,不论是继承Thread类还是实现Runnable接口,要想实现多线程的处理逻辑就要重写run()方法。

因为默认的run()是不干活的,该方法来源于接口Runnable

1
2
3
4
@FunctionalInterface
public interface Runnable {
void run();
}

Thread类也实现了这个接口,这也是其run()的来源

1
public class Thread implements Runnable {...}

看到这里,你可能有点糊涂,感觉没什么问题,但有什么地方是不通的。可能会有这样的疑问:Runnable是什么? Thread又是什么?

还记得Java最最最重要的特点吗? 万物皆对象,一切都围绕 “ 对象行为(方法)+ 状态(属性)” 来组织。在这种思想下,“逻辑”本身也可以抽象成一个对象。Runnable 就是一个对“任务逻辑”的对象化表达。

Runnable 接口是什么?

1
2
3
4
@FunctionalInterface
public interface Runnable {
void run();
}

这是个函数式接口,里面只有一个抽象方法run(),表示要执行的任务逻辑
换句话说,Runnable是对“任务”的对象化封装,将任务执行的逻辑封装成对象交给线程去执行。

来看一段代码:

1
2
Runnable task = () -> System.out.println("Running in thread!");
new Thread(task).start();
  • task 是一个对象(它实现了 Runnable 接口);
  • 它代表一段“行为”;
  • 我们把它传给 Thread 类构造方法,Thread 就知道该线程该执行什么内容。

start() 和 run()

Thread.start() 是启动线程的入口,不能直接调用 run(),那只是普通方法调用!

只有调用start()方法,在栈中才会创建一个线程!