多线程实例代码(demo)

简介: 多线程实例代码(demo)

多线程是什么?


在介绍多线程的时候,我们首先要知道什么是线程,而要了解线程还要了解进程。

1.进程:一个正在执行中的程序,每个进程执行都有一个执行顺序,该顺序是一个执行路径,或者是一个控制单元。

2.线程:进程中的一个独立控制单元,线程在控制进程的执行。一个进程中至少有一个线程。

3.多线程:一个进程中不只有一个线程。

eg:比如我们开车从北京到上海,进程可以理解为我们在去的上海的路上,坐飞机去相当于一个进程,我们不只只可以坐飞机还可坐高铁,自驾等这便是我们上面说的多线程。


原理:

多线程就是把操作系统中的这种并发执行机制原理运用在一个程序中,把一个程序划分为若干个子任务,多个子任务并发执行,每一个任务就是一个线程。


实现多线程是采用一种并发执行机制。


优势

1、方便的通信和数据交换


2、更高效地利用CPU


3、线程与进程的区别


线程 是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行. 一个进程最少 有一个线程,线程实际上是在进程基础之上的进一步划分,一个进程启动之后,里面的若干执行路径又可以划分成若干个线程。


进程 是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间


我们为什么要用多线程呢?


为了更好地利用CPU的资源,如果只有一个线程,我们有多个任务的时候必须等着上一个任务完成才能进行。多线程则不用等待可在主线程执行的同时执行其他任务。

进程之间不可以共享数据,但是 线程可以。


系统创建进程需要为该进程重新分配系统资源,创建线程代价少。

Java语言内置了多线程功能支持,简化了Java多线程编程。


CompletionService是什么?

Callable+Future 可以实现多个task并行执行,但是如果遇到前面的task执行较慢时需要阻塞等待前面的task执行完后面task才能取得结果。


CompletionService的主要功能就是一边生成任务,一边获取任务的返回值。让两件事分开执行,任务之间不会互相阻塞,可以实现先执行完的先取结果,不再依赖任务顺序了。


他只有一个实现类:ExecutorCompletionService


CompletionService原理

内部通过阻塞队列+FutureTask,实现了任务先完成可优先获取到,即结果按照完成先后顺序排序,内部有一个先进先出的阻塞队列,用于保存已经执行完成的Future,通过调用它的take方法或poll方法可以获取到一个已经执行完成的Future,进而通过调用Future接口实现类的get方法获取最终的结果。


CompletionService的应用场景

当需要批量提交异步任务的时候建议你使用CompletionService:CompletionService将线程池Executor和阻塞队列BlockingQueue的功能融合在了一起,能够让批量异步任务的管理更简单。


CompletionService能够让异步任务的执行结果有序化:先执行完的先进入阻塞队列,利用这个特性,你可以轻松实现后续处理的有序性,避免无谓的等待,同时还可以快速实现诸如Forking Cluster这样的需求。


线程池隔离:CompletionService支持自己创建线程池,这种隔离性能避免几个特别耗时的任务拖垮整个应用的风险。


虽然使用了线程池提高了整体的执行效率,但遍历这些Future,调用Future接口实现类的get方法是阻塞的,也就是和当前这个Future关联的计算任务真正执行完成的时候,get方法才返回结果,如果当前计算任务没有执行完成,而有其它Future关联的计算任务已经执行完成了,就会白白浪费很多等待的时间,所以最好是遍历的时候谁先执行完成就先获取哪个结果,这样就节省了很多持续等待的时间。


而ExecutorCompletionService可以实现这样的效果,它的内部有一个先进先出的阻塞队列,用于保存已经执行完成的Future,通过调用它的take方法或poll方法可以获取到一个已经执行完成的Future,进而通过调用Future接口实现类的get方法获取最终的结果


ExecutorCompletionService实现了CompletionService接口,在CompletionService接口中定义了如下这些方法:


Future submit(Callable task):提交一个Callable类型任务,并返回该任务执行结果关联的Future;


Future submit(Runnable task,V result):提交一个Runnable类型任务,并返回该任务执行结果关联的Future;


Future take():从内部阻塞队列中获取并移除第一个执行完成的任务,阻塞,直到有任务完成;


Future poll():从内部阻塞队列中获取并移除第一个执行完成的任务,获取不到则返回null,不阻塞;


Future poll(long timeout, TimeUnit unit):从内部阻塞队列中获取并移除第一个执行完成的任务,阻塞时间为timeout,获取不到则返回null;

package com.example.yanwc;
import java.util.Random;
import java.util.concurrent.*;
public class Deadlock {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(5);
        // 创建CompletionService
        CompletionService<Integer> cs = new ExecutorCompletionService<>(executor);
        // 开启5个任务
        for (int i = 0; i < 5; i++) {
            cs.submit(new CompletionTask());
        }
        // 将询价结果异步保存到数据库
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + " 获取到任务结果:" + cs.take().get());
        }
    }
}
/**
 * 自定义的任务
 */
class CompletionTask implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        // 获取随机的世界
        int randomSleepTime = new Random().nextInt(10) * 1000;
        // 开始执行
        System.out.println(Thread.currentThread().getName() + " 开始执行,当前任务需要等待" + randomSleepTime + "毫秒");
        // 线程等待,模拟正在执行
        TimeUnit.MILLISECONDS.sleep(randomSleepTime);
        // 结束执行
        System.out.println(Thread.currentThread().getName() + "结束执行,当前任务需要等待" + randomSleepTime + "毫秒");
        // 返回他等待的时间
        return randomSleepTime;
    }
}
E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\bin\java.exe -javaagent:D:\idea\idea20203pj_186103\lib\idea_rt.jar=51798:D:\idea\idea20203pj_186103\bin -Dfile.encoding=UTF-8 -classpath E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\charsets.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\deploy.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\ext\access-bridge-64.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\ext\cldrdata.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\ext\dnsns.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\ext\jaccess.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\ext\jfxrt.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\ext\localedata.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\ext\nashorn.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\ext\sunec.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\ext\sunjce_provider.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\ext\sunmscapi.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\ext\sunpkcs11.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\ext\zipfs.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\javaws.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\jce.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\jfr.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\jfxswt.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\jsse.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\management-agent.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\plugin.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\resources.jar;E:\JAVA-JIHE\JDK\java\jdk1.8.0_162\jre\lib\rt.jar;F:\IDEA_gulimall\Login_Register\yanwc\target\classes;D:\maven\apache-maven-3.5.3-bin\repository\org\springframework\boot\spring-boot-starter-thymeleaf\2.2.4.RELEASE\spring-boot-starter-thymeleaf-2.2.4.RELEASE.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\springframework\boot\spring-boot-starter\2.2.4.RELEASE\spring-boot-starter-2.2.4.RELEASE.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\springframework\boot\spring-boot\2.2.4.RELEASE\spring-boot-2.2.4.RELEASE.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\springframework\boot\spring-boot-autoconfigure\2.2.4.RELEASE\spring-boot-autoconfigure-2.2.4.RELEASE.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\springframework\boot\spring-boot-starter-logging\2.2.4.RELEASE\spring-boot-starter-logging-2.2.4.RELEASE.jar;D:\maven\apache-maven-3.5.3-bin\repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\maven\apache-maven-3.5.3-bin\repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\apache\logging\log4j\log4j-to-slf4j\2.12.1\log4j-to-slf4j-2.12.1.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\apache\logging\log4j\log4j-api\2.12.1\log4j-api-2.12.1.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;D:\maven\apache-maven-3.5.3-bin\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\yaml\snakeyaml\1.25\snakeyaml-1.25.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\thymeleaf\thymeleaf-spring5\3.0.11.RELEASE\thymeleaf-spring5-3.0.11.RELEASE.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\thymeleaf\thymeleaf\3.0.11.RELEASE\thymeleaf-3.0.11.RELEASE.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\attoparser\attoparser\2.0.5.RELEASE\attoparser-2.0.5.RELEASE.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\unbescape\unbescape\1.1.6.RELEASE\unbescape-1.1.6.RELEASE.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\thymeleaf\extras\thymeleaf-extras-java8time\3.0.4.RELEASE\thymeleaf-extras-java8time-3.0.4.RELEASE.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\springframework\boot\spring-boot-starter-web\2.2.4.RELEASE\spring-boot-starter-web-2.2.4.RELEASE.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\springframework\boot\spring-boot-starter-json\2.2.4.RELEASE\spring-boot-starter-json-2.2.4.RELEASE.jar;D:\maven\apache-maven-3.5.3-bin\repository\com\fasterxml\jackson\core\jackson-databind\2.10.2\jackson-databind-2.10.2.jar;D:\maven\apache-maven-3.5.3-bin\repository\com\fasterxml\jackson\core\jackson-annotations\2.10.2\jackson-annotations-2.10.2.jar;D:\maven\apache-maven-3.5.3-bin\repository\com\fasterxml\jackson\core\jackson-core\2.10.2\jackson-core-2.10.2.jar;D:\maven\apache-maven-3.5.3-bin\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.10.2\jackson-datatype-jdk8-2.10.2.jar;D:\maven\apache-maven-3.5.3-bin\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.10.2\jackson-datatype-jsr310-2.10.2.jar;D:\maven\apache-maven-3.5.3-bin\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.10.2\jackson-module-parameter-names-2.10.2.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\springframework\boot\spring-boot-starter-tomcat\2.2.4.RELEASE\spring-boot-starter-tomcat-2.2.4.RELEASE.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.30\tomcat-embed-core-9.0.30.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\apache\tomcat\embed\tomcat-embed-el\9.0.30\tomcat-embed-el-9.0.30.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.30\tomcat-embed-websocket-9.0.30.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\springframework\boot\spring-boot-starter-validation\2.2.4.RELEASE\spring-boot-starter-validation-2.2.4.RELEASE.jar;D:\maven\apache-maven-3.5.3-bin\repository\jakarta\validation\jakarta.validation-api\2.0.2\jakarta.validation-api-2.0.2.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\hibernate\validator\hibernate-validator\6.0.18.Final\hibernate-validator-6.0.18.Final.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\jboss\logging\jboss-logging\3.4.1.Final\jboss-logging-3.4.1.Final.jar;D:\maven\apache-maven-3.5.3-bin\repository\com\fasterxml\classmate\1.5.1\classmate-1.5.1.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\springframework\spring-web\5.2.3.RELEASE\spring-web-5.2.3.RELEASE.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\springframework\spring-beans\5.2.3.RELEASE\spring-beans-5.2.3.RELEASE.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\springframework\spring-webmvc\5.2.3.RELEASE\spring-webmvc-5.2.3.RELEASE.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\springframework\spring-aop\5.2.3.RELEASE\spring-aop-5.2.3.RELEASE.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\springframework\spring-context\5.2.3.RELEASE\spring-context-5.2.3.RELEASE.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\springframework\spring-expression\5.2.3.RELEASE\spring-expression-5.2.3.RELEASE.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\projectlombok\lombok\1.18.10\lombok-1.18.10.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\springframework\spring-core\5.2.3.RELEASE\spring-core-5.2.3.RELEASE.jar;D:\maven\apache-maven-3.5.3-bin\repository\org\springframework\spring-jcl\5.2.3.RELEASE\spring-jcl-5.2.3.RELEASE.jar com.example.yanwc.Deadlock
pool-1-thread-4 开始执行,当前任务需要等待2000毫秒
pool-1-thread-3 开始执行,当前任务需要等待0毫秒
pool-1-thread-3结束执行,当前任务需要等待0毫秒
pool-1-thread-2 开始执行,当前任务需要等待2000毫秒
pool-1-thread-5 开始执行,当前任务需要等待2000毫秒
pool-1-thread-1 开始执行,当前任务需要等待7000毫秒
main 获取到任务结果:0
pool-1-thread-2结束执行,当前任务需要等待2000毫秒
pool-1-thread-4结束执行,当前任务需要等待2000毫秒
pool-1-thread-5结束执行,当前任务需要等待2000毫秒
main 获取到任务结果:2000
main 获取到任务结果:2000
main 获取到任务结果:2000
pool-1-thread-1结束执行,当前任务需要等待7000毫秒
main 获取到任务结果:7000
package com.example;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class DeadLock2 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Integer i = 1;
        Integer ii = 2;
        Integer iii = 3;
        Integer iiii = 4;
        List<Integer> list = new ArrayList<>();
        //把相关参数传入list集合
        list.add(i);
        list.add(ii);
        list.add(iii);
        list.add(iiii);
        System.out.println("转换前" + list);
        //线程返回对象
        List<Future<Integer>> l = new ArrayList<>();
        //  创建线程池等待队列
        BlockingQueue q = new LinkedBlockingQueue();
        //创建线程池并建立相关的参数
        // 创建线程对象 开启多线程
        ThreadPoolExecutor executor = new ThreadPoolExecutor(4,6,3, TimeUnit.SECONDS,q);
        //线程 用来执行任务
        CompletionService<Integer> completionService = new ExecutorCompletionService(executor);
        //for循环
        for (Integer integer : list) {
            Future<Integer> future = completionService.submit(wc(integer));
            l.add(future);
        }
        List<Integer> ll = new ArrayList<>();
        //实例化数据
        for (Future<Integer> future : l) {
            ll.add(future.get());
        }
        System.out.println("转换后" + ll);
    }
    private static Callable<Integer> wc(Integer integer) {
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                return integer + 1;
            }
        };
        return callable;
    }
}


运行结果:

转换前[1, 2, 3, 4]
转换后[2, 3, 4, 5]


构造方法解析:

CompletionService的构造方法源码分析

/**


传入线程池的构造方法

*/

public ExecutorCompletionService(Executor executor) {
    // 线程池为null,直接抛出异常
    if (executor == null)
        throw new NullPointerException();
    // 把使用的线程池赋值
    this.executor = executor;
    // 判断是不是AbstractExecutorService的子类
    this.aes = (executor instanceof AbstractExecutorService) ?
        (AbstractExecutorService) executor : null;
    // 默认只是用LinkedBlockingQueue进行结果的存放
    this.completionQueue = new LinkedBlockingQueue<Future<V>>();
}
/**
 * 传入线程池的构造方法和使用的队列
 */
public ExecutorCompletionService(Executor executor,
                                 BlockingQueue<Future<V>> completionQueue) {
    // 线程池为null或者使用的队列为空,直接抛出异常
    if (executor == null || completionQueue == null)
        throw new NullPointerException();
    // 把使用的线程池赋值
    this.executor = executor;
    // 判断是不是AbstractExecutorService的子类
    this.aes = (executor instanceof AbstractExecutorService) ?
        (AbstractExecutorService) executor : null;
    // 使用传入的队列进行结果的存放
    this.completionQueue = completionQueue;
}
CompletionService的submit方法源码分析
/**
 * CompletionService的任务提交方法
 */
public Future<V> submit(Runnable task, V result) {
    // 任务为空,抛出空指针异常
    if (task == null) throw new NullPointerException();
    // 创建一个具体的任务
    RunnableFuture<V> f = newTaskFor(task, result);
    // 执行这个任务:封装一下,重写了done方法,将运行结果放入队列中。
    executor.execute(new QueueingFuture(f));
    // 返回执行的结果
    return f;
}
/**
 * QueueingFuture类:他重写了done方法
 */
private class QueueingFuture extends FutureTask<Void> {
    QueueingFuture(RunnableFuture<V> task) {
        super(task, null);
        this.task = task;
    }
    // 执行完成的方法:运行结果放入队列中。
    protected void done() { completionQueue.add(task); }
    private final Future<V> task;
}
CompletionService的take方法源码分析
/**
 * CompletionService的出队take方法:直接调用队列的阻塞出队方法。
 */
public Future<V> take() throws InterruptedException {
    return completionQueue.take();
}
相关文章
|
2月前
多线程案例-定时器(附完整代码)
多线程案例-定时器(附完整代码)
245 0
|
4月前
|
数据采集 Python
【Python自动化】多线程BFS站点结构爬虫代码,支持中断恢复,带注释
【Python自动化】多线程BFS站点结构爬虫代码,支持中断恢复,带注释
30 0
|
4月前
|
Java
Java使用线程池代码
Java使用线程池代码
36 0
|
4月前
|
Java
|
12天前
多线程售票demo,用ReentrantLock实现
多线程售票demo,用ReentrantLock实现
|
1月前
|
Python
Python 多线程运用 demo
这是一个Python多线程示例,创建了两个线程`t1`和`t2`分别执行`print_numbers`(打印0-9)和`print_letters`(打印&#39;a&#39;-&#39;j&#39;)函数。通过`start()`启动线程,`join()`确保线程执行完毕后输出&quot;程序结束&quot;。
10 2
|
2月前
|
消息中间件 并行计算 网络协议
探秘高效Linux C/C++项目架构:让进程、线程和通信方式助力你的代码飞跃
探秘高效Linux C/C++项目架构:让进程、线程和通信方式助力你的代码飞跃
41 0
|
2月前
|
数据采集 调度 计算机视觉
3段代码详解python中的单线程、多线程和多进程
3段代码详解python中的单线程、多线程和多进程
25 0
|
4月前
|
消息中间件 Java Linux
C语言-线程池代码
github 地址:常用的C工具代码,这里的工具包含了C语言实现的线程池,hashtable,list,md5,字符串操作,消息队列等很多常用的工具,我这里就不一一说明了,感兴趣的朋友可以自行下载研究,工作中肯定用的上。
39 0
|
4月前
|
NoSQL Java 应用服务中间件
线程池详解及完整代码实现
线程池详解及完整代码实现