1.搞懂一些概念
java多线程操作是中高级程序员的基本操作。要实现多线程,就要先了解几个概念。
(1)程序(program):程序是一组计算机能识别和执行的指令,我们写的一堆代码组成一个或多个程序。
(2)进行(Process): 将程序运行起来就是一个进程。比如我们打开我们电脑的任务管理器,切换到进程这个标签,可以看到有很多的进程。

(3)线程(Thread):线程是程序中是实际执行者,是最小的执行单位。一个进程包含一个或多个线程。比如我们点开上面的谷歌浏览器,下面展示的就是谷歌浏览器的线程。

(4)单核CPU:单核CPU的多线程都是模拟出来的,都是“假的”。CPU在同一个时间周期内只能执行一个代码,只不过来回切换的特别快,看不出来。
(5) 多核CPU: 多核CPU的多线程是真正的多线程。现在的服务器都是多核的。查看你当前电脑是否是多核很简单,打开任务管理器。切换到性能那一栏

上面的图片就是表示当前CPU是8核。(这里的逻辑处理器指的是逻辑处理器指的就是支持超线程技术的处理器在一个单核心的CPU内,利用其中空闲的执行单元,模拟出另外一个核心,使整个CPU有两个逻辑核心,从而提高整个CPU的工作效率)
(6) 并发:并发是指在同一时间段内,有多个任务在交替执行。在多任务操作系统中,多个任务可以在同一时间共享CPU,因此表现出来的是并发执行的状态。(因为切换的很快,所以感觉起来像并发)
(7) 并行:并行是指在同一时间段内,有多个任务同时执行。在多处理器系统中,不同的处理器可以同时执行不同的任务,因此表现出来的是并行执行的状态。
(8) 串行:按照顺序一个一个执行程序,就是串行执行。
2.使用多线程的情景
- 处理并行任务:多线程可以同时处理多个任务,提高程序的执行效率。比如批量处理数据、同时上传多个文件等。
- 事件驱动的编程:Java多线程可以用于事件驱动的编程,如GUI、网络编程等。
- 并发访问共享资源:多线程可以应用于并发访问共享资源的场景,如数据库连接池。
- 高效的IO操作:在网络编程中,Java多线程可以提供高效的IO操作,如同时读写多个Socket。
- 多任务协同处理:在复杂的任务中,不同的任务可以以各自独立的方式并行运行,最终合并结果。
- 提高用户体验:在一些高并发场景下,如网站、游戏等,使用多线程可以提高用户体验,使得用户能够更快地得到反馈。
3.多线程实现方式
JAVA实现多线程的方式一般有三种:继承Thread类、实现Runnable接口、实现Callable接口。
- 继承Thread类
Thread类本质上是实现了Runnable接口的一个实例,代表一个线程的实例。启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。例如:
//多线程测试 @SpringBootTest public class ThreadTests { //多线程的自定义方法(以吃晚饭为例) public static void eatDinner(String name) { System.out.println(name + "做饭"); System.out.println(name + "吃饭中"); System.out.println(name + "洗碗"); } //启动启动!! public static void main(String[] args) { thread th1 = new thread("线程1"); thread th2 = new thread("线程2"); thread th3 = new thread("线程3"); th1.start(); th2.start(); th3.start(); } } //定义多线程 class thread extends Thread{ String name; public thread(String name) { this.name = name; } //重写run方法 @Override public void run() { ThreadTests.eatDinner(name); //调用自定义方法查看区别 } }
实现效果:

- 实现Callable接口
//多线程测试(Callable方式) @SpringBootTest public class ThreadCallableTest { //多线程的自定义方法(以吃晚饭为例) public static void eatDinner(String name) { System.out.println(name + "做饭"); System.out.println(name + "吃饭中"); System.out.println(name + "吃完饭洗碗"); } //启动启动!! public static void main(String[] args) throws ExecutionException, InterruptedException{ //定义线程对象 MyCallable th1 = new MyCallable("线程1-->"); MyCallable th2 = new MyCallable("线程2-->"); MyCallable th3 = new MyCallable("线程3-->"); FutureTask ft1 = new FutureTask<>(th1); FutureTask ft2 = new FutureTask<>(th2); FutureTask ft3 = new FutureTask<>(th3); Thread thread1 = new Thread(ft1); Thread thread2 = new Thread(ft2); Thread thread3 = new Thread(ft3); thread1.start(); thread2.start(); thread3.start(); //也可以获取返回值 Object obj1 = ft1.get(); System.out.println(obj1); //返回10以内的随机数 Object obj2 = ft2.get(); System.out.println(obj2); //返回10以内的随机数 Object obj3 = ft3.get(); System.out.println(obj3); //返回10以内的随机数 } } //创建一个实现Callable的实现类 class MyCallable implements Callable { String name; public MyCallable(String name) { this.name = name; } /** * 实现call方法,将此线程需要执行的操作声明在call()中 * 方法有返回值,可以抛出异常。 * */ @Override public Integer call() throws Exception { ThreadCallableTest.eatDinner(name); //实现自定义方法 return new Random().nextInt(10); //返回10以内的随机数; } }
实现效果:

- 实现Runnable接口
实现Runnable接口也是一种常见的创建线程的方式,使用接口的方式可以让我们的程序降低耦合度。Runnable接口中仅仅定义了一个方法,就是run。
具体流程
- 定义一个类实现Runnable接口,作为线程任务类
- 重写run方法,并实现方法体,方法体的代码就是线程所执行的代码
- 定义一个可以运行的类,并在main方法中创建线程任务类
- 创建Thread类,并将线程任务类做为Thread类的构造方法传入
- 启动线程
//多线程测试(Runnable方式) @SpringBootTest public class ThreadRunnableTest { //多线程的自定义方法(以吃晚饭为例) public static void eatDinner(String name) { System.out.println(name + "做饭"); System.out.println(name + "吃饭中"); System.out.println(name + "吃完饭洗碗"); } //启动启动!! public static void main(String[] args) { MyRunnable runnable1 = new MyRunnable("Runnable方式,线程1-->"); MyRunnable runnable2 = new MyRunnable("Runnable方式,线程2-->"); MyRunnable runnable3 = new MyRunnable("Runnable方式,线程3-->"); Thread th1 = new Thread(runnable1); Thread th2 = new Thread(runnable2); Thread th3 = new Thread(runnable3); th1.start(); th2.start(); th3.start(); } } //定义多线程 class MyRunnable implements Runnable{ String name; public MyRunnable(String name) { this.name = name; } //重写run方法 @Override public void run() { ThreadRunnableTest.eatDinner(name); //调用自定义方法查看区别 } }
实现效果:
