新时代码农必备的三种多线程的写法!!!
作为新生代农名工中的码农,我们耳熟能详的三个关键字进程、线程、协程。那么这三者到底是什么呢?【免费干货】多线程从入门到精通
- 进程: 是系统进行资源分配和调度的基本单位,是程序的实体,给线程提供环境,包括数据区域和堆栈存储着活动过程调用的指令和本地的变量。一个程序可能有多个进程,比如nginx启动的时候就会有多个进程,可使用命令
ps -ef |grep nginx
查看nginx的进程。 - 线程:是程序执行流的最小单元,一个进程可以有一个或多个线程,同一进程中的多个线程将共享该进程中的全部系统资源,正是由于多线程,我们的程序才能同时做不同的事。
- 协程:比线程更加轻量级的存在,一个线程中可以有任意多个协程,但某一时刻只能有一个协程在运行。
java基础巩固也是必不可少的,大家都要学习呀!!!
多线程是程序面对高并发时不可或缺的东西,也是面试中最多被问的问题,多线程在java中有三种写法,你都用过吗?快来一起温习温习:
- 1、继承Thread类
- 2、实现Runnable接口
- 3、实现Callable接口
继承Thread类
只需要继承Thread类,重写run方法即可。run方法的内容就是线程执行的内容。
package com.wangscaler.thread; /** * @author WangScaler * @date 2021/8/17 14:00 */ public class Demo { public static void main(String[] args) { Thread thread = new Thread() { @Override public void run() { System.out.println("wangscaler"); } }; thread.start(); } }
这种方式实现简单,当然也可以使用lamba表达式更简单的实现。
package com.wangscaler.thread; /** * @author WangScaler * @date 2021/8/17 14:00 */ public class Demo { public static void main(String[] args) { Thread thread = new Thread(() -> System.out.println("wangscaler")); thread.start(); } }
但是java是单继承,一旦继承Thread将无法继承其他的类,而且这种方式也没有返回值。属于上手容易,使用不方便的类。
实现Runnable接口
实现Runnable接口的方法,不仅可以避免单继承的问题,还可以实现数据共享。相对于继承Thread类有了较大的优势,不过还是有着他自己的缺点。
package com.wangscaler.thread; /** * @author WangScaler * @date 2021/8/17 14:00 */ public class Demo { public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println("wangscaler"); } }); thread.start(); } }
这种方法的缺点就是没有返回值。
实现Callable接口
相对于Runnable增加了返回值。
package com.wangscaler.thread; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; /** * @author WangScaler * @date 2021/8/17 14:00 */ public class Demo { public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask<Integer>task = new FutureTask<>(new Callable<Integer>() { @Override public Integer call() throws Exception { System.out.print("hello\t"); return 0; } }); Thread thread =new Thread(task); thread.start(); if(task.get().equals(0)){ System.out.println("wangscaler"); } } }
在我们程序中,耗时而没有数据依赖(不影响下面代码执行)的代码,可以用这个线程去执行。比如我们的日志文件就可以用单独的线程写库,在程序的最后来获取线程的执行结果来判断线程执行成功与否。
注意:
- 1、
task.get()
执行 时,如果线程task还没有执行完毕,会导致调用的线程阻塞,直到task线程执行结束为止,所以一定要放在程序的最后。 - 2、多个Thread启动一个FutureTask。只会执行一遍,如果想执行多编,那么你必须创建多个FutureTask
总结
除了上述Callable有返回值之外,另一个区别就是call方法可以抛出异常,而run方法不可以。在正式开发中,前两种的使用越来越少,取而代之的就是线程池,下节课再来讲述这个比今天更重要的知识,今天就到这里吧。
任何时候都不能停止学习的脚步,编程亦是如此,需要勤加练习,多加温习,巩固基础,方成大事