新时代码农必备的三种多线程的写法!!!

作为新生代农名工中的码农,我们耳熟能详的三个关键字进程、线程、协程。那么这三者到底是什么呢?【免费干货】多线程从入门到精通

  • 进程: 是系统进行资源分配和调度的基本单位,是程序的实体,给线程提供环境,包括数据区域和堆栈存储着活动过程调用的指令和本地的变量。一个程序可能有多个进程,比如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方法不可以。在正式开发中,前两种的使用越来越少,取而代之的就是线程池,下节课再来讲述这个比今天更重要的知识,今天就到这里吧。

任何时候都不能停止学习的脚步,编程亦是如此,需要勤加练习,多加温习,巩固基础,方成大事

 

posted @ 2021-08-19 10:23  菜菜爱分享  阅读(179)  评论(0编辑  收藏  举报