多线程实例代码(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();
}
相关文章
|
4月前
|
安全 Python
告别低效编程!Python线程与进程并发技术详解,让你的代码飞起来!
【7月更文挑战第9天】Python并发编程提升效率:**理解并发与并行,线程借助`threading`模块处理IO密集型任务,受限于GIL;进程用`multiprocessing`实现并行,绕过GIL限制。示例展示线程和进程创建及同步。选择合适模型,注意线程安全,利用多核,优化性能,实现高效并发编程。
74 3
|
6月前
|
设计模式 监控 Java
Java多线程基础-11:工厂模式及代码案例之线程池(一)
本文介绍了Java并发框架中的线程池工具,特别是`java.util.concurrent`包中的`Executors`和`ThreadPoolExecutor`类。线程池通过预先创建并管理一组线程,可以提高多线程任务的效率和响应速度,减少线程创建和销毁的开销。
215 2
|
2月前
自己动手写QT多线程demo
本文是作者关于如何编写Qt多线程demo的教程,介绍了如何实现多线程功能,包括可暂停和继续的功能。文章提供了部分示例代码,展示了如何创建线程类、启动和管理线程,以及线程间的通信。同时,还提供了相关参考资料和免费下载链接。
|
3月前
|
Java Windows
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
|
3月前
|
Java 开发者
解锁Java并发编程的秘密武器!揭秘AQS,让你的代码从此告别‘锁’事烦恼,多线程同步不再是梦!
【8月更文挑战第25天】AbstractQueuedSynchronizer(AQS)是Java并发包中的核心组件,作为多种同步工具类(如ReentrantLock和CountDownLatch等)的基础。AQS通过维护一个表示同步状态的`state`变量和一个FIFO线程等待队列,提供了一种高效灵活的同步机制。它支持独占式和共享式两种资源访问模式。内部使用CLH锁队列管理等待线程,当线程尝试获取已持有的锁时,会被放入队列并阻塞,直至锁被释放。AQS的巧妙设计极大地丰富了Java并发编程的能力。
44 0
|
5月前
|
API
linux---线程互斥锁总结及代码实现
linux---线程互斥锁总结及代码实现
|
5月前
|
Java
【代码诗人】Java线程的生与死:一首关于生命周期的赞歌!
【6月更文挑战第19天】Java线程生命周期,如诗般描绘了从新建到死亡的旅程:创建后待命,`start()`使其就绪,获得CPU则运行,等待资源则阻塞,任务完或中断即死亡。理解生命周期,善用锁、线程池,优雅处理异常,确保程序高效稳定。线程管理,既是艺术,也是技术。
30 3
|
5月前
|
Java
【代码诗人】Java线程的生与死:一首关于生命周期的赞歌!
【6月更文挑战第19天】在Java中,线程经历新建、就绪、运行、阻塞和死亡5个阶段。通过`start()`从新建转为就绪,进而可能运行;阻塞可能因等待资源;完成任务或中断后死亡。管理线程生命周期涉及合理使用锁、线程池、异常处理和优雅关闭,如使用`volatile`和中断标志。了解这些,能提升程序效率和稳定性。
27 2
|
5月前
|
API
Linux---线程读写锁详解及代码实现
Linux---线程读写锁详解及代码实现
|
6月前
|
设计模式 安全 Java
多线程(代码案例: 单例模式, 阻塞队列, 生产者消费者模型,定时器)
多线程(代码案例: 单例模式, 阻塞队列, 生产者消费者模型,定时器)
57 2