线程与进程:
通俗地说,线程和进程都是计算机中用来执行任务的基本单位,就像工厂里的工人一样。
进程(Process): 想象一家工厂,每个工厂都可以生产不同的产品,有自己的原材料、设备和工人。在计算机中,一个进程就像是运行在计算机上的一个独立的工厂,有自己的代码、数据和资源。每个进程都在自己的“工厂”里进行独立的工作,相互之间不会直接影响。一个进程可以包含多个线程。
线程(Thread): 现在,想象工厂里的一个工人,工人可以独立地进行一些任务,比如装配产品。在计算机中,一个线程就像是进程中的一个工人,可以在同一个进程内与其他线程共享代码和数据。线程可以同时进行多个任务,就像工人可以同时处理不同的工作。
简而言之,进程就是一个独立的工厂,而线程是在这个工厂内部独立工作的工人。进程之间相互隔离,而线程可以共享同一个进程内的资源。计算机利用进程和线程来有效地执行多个任务,就像工厂同时生产多种产品一样。
多线程:
多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理或同时多线程处理器。在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理”
实现多线程的几种方式
1,继承Thread 2,实现Runnable接口 3,实现Callable接口结合FutureTask(可以拿到返回结果 可以异常处理) 4线程池 区别: 1,2 不能得到返回值 3可以 1,2,3 都不能控制资源 4可以控制资源 新能稳定
// 继承Thread类
public static class Thread01 extends Thread {
@Override
public void run() {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
}
}
Thread01 thread01 = new Thread01();
thread01.start();// 启动线程
// 实现Runnable
public static class Runnable01 implements Runnable{
@Override
public void run() {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
}
}
Runnable01 runnable01 = new Runnable01();
new Thread(runnable01).start();
// 实现Callable接口 结合FutureTask
public static class Callable01 implements Callable<Integer>{
@Override
public Integer call() throws Exception {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
return i;
}
}
FutureTask<Integer> integerFutureTask = new FutureTask<>(new Callable01());
new Thread(integerFutureTask).start();
// 阻塞等待整个线程执行完成获取返回结果
Integer integer = integerFutureTask.get();
//线程池
public static ExecutorService executor = Executors.newFixedThreadPool(10);
ExecutorService executorService = Executors.newCachedThreadPool();//核心是零
executorService.execute(new Runnable01());
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.execute(new Runnable01());//固定线程数core=max都不可回收
Executors.newScheduledThreadPool();//定时任务的线程池
Executors.newSingleThreadExecutor();//单线程的线程池 后台从队列中获取任务挨个执行
自定义线程池:
线程池七大参数 int corePoolSize:核心线程数:一直存在触发设置超时时间 int maximumPoolSize:最大线程数:控制资源 long keepAliveTime:空闲线程保留时间:当前线程数大于核心线程数时释放超过核心线程数的线程 TimeUnit unit:时间单位 BlockingQueue<Runnable> workQueue:工作阻塞队列:如果任务有很多就会将目前多的任务放进队里 有线程空闲就去队列里取出新任务执行 ThreadFactory threadFactory:线程工厂 RejectedExecutionHandler handler:拒绝策略:如果队列满了按照指定的策略拒绝任务 工作顺序 1, 线程池创建 准备好核心线程数准备接收任务 1.1 核心线程占满了 就将再进来的任务放进阻塞队列中 空闲的核心线程会自行去队列里获取任务并执行 1.2 阻塞队列满了 就直接开新线程执行 最大只能开到最大线程数的数量 LinkedBlockingQueue<>()默认Integer的最大值 会导致内存被占满 1.3 最大线程数也满了 就拒绝 1.4 最大线程里的任务执行完了有很多空闲线程 在指定的时间后释放线程至核心线程数 一个线程池 core 7 ,max 20,queue 50,100并发怎么分配 7个会立即执行 50个会进队列 最大线程会另外占13个 剩下的30使用拒绝策略
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,
200,
10,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(10000),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
异步编排:CompletableFuture
异步编排是让程序并发运行的一种手段。它允许多个事件同时发生,当程序调用需要长时间运行的方法时,它不会阻塞当前的执行流程,程序可以继续运行。
public class CompletableFutureTest {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("-----------------main----start---------------");
/*
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { // 启动异步任务 执行lamda表达式中的语句 用executor线程池
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
}, executor);
*/
/**
* 方法完成后的感知
*/
/*
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 0;
System.out.println("运行结果:" + i);
return i;
}, executor).whenComplete((res,exception) -> {
// whenComplete虽然能得到异常信息 但是无法修改返回数据 (类似监听器)
System.out.println("异步任务完成了 结果是:"+res+" 异常:"+exception);
}).exceptionally(throwable -> {
// 可以感知异常 返回默认值
return 10;
});
Integer integer = future.get(); // 需抛出异常
Integer integer1 = future.join(); // 无需抛出异常
*/
/**
* 方法执行完后的处理
*/
/*
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(()->{
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
return i;
},executor).handle((res,thr)->{
if (res != null) {
System.out.println("res:"+res);
return res*2;
}
if (thr!=null){
System.out.println("thr: " + thr);
return 0;
}
return 0;
});
Integer integer = future.get();
*/
/**
* 线程串行化
* 1),thenRunAsync: 不能获取上一步的执行结果
* thenRunAsync(()->{
* System.out.println("任务2启动了");
* },executor);
*
* 2),thenAcceptAsync: 能回去上一步的结果但不能改变返回值
* thenAcceptAsync(res->{
* System.out.println("任务2启动了 res:"+res);
* },executor);
*
* 3),thenApplyAsync: 既能接收上一步的结果 还有返回值
* thenApplyAsync(res -> {
* System.out.println("任务2启动了 res:" + res);
* return "thenApplyAsync " + res;
* }, executor);
*/
/*
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
return i;
}, executor).thenApplyAsync(res -> {
System.out.println("任务2启动了 res:" + res);
return "thenApplyAsync " + res;
}, executor);
*/
/**
* 任务组合
*/
/*
CompletableFuture<Object> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务1线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("任务1结束:" + i);
return i;
}, executor);
CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务2线程:" + Thread.currentThread().getId());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任务2结束");
return "hello";
}, executor);
*/
/**
* 两个都完成后再执行....
* 1),runAfterBothAsync:不能感知前两个执行的结果无返回值CompletableFuture<Void>
* future1.runAfterBothAsync(future2,()-> System.out.println("任务3开始"), executor);
*
* 2),thenAcceptBothAsync:可以感知前两个的返回结果 无返回值CompletableFuture<Void>
* future1.thenAcceptBothAsync(future2,(f1,f2)->{
* System.out.println("任务3开始 得到f1:" + f1+" f2:" + f2);
* },executor);
*
* 3),thenCombineAsync:可以感知前两个的返回结果 而且有返回值CompletableFuture<T>
*/
// CompletableFuture<Void> future3 = future1.runAfterBothAsync(future2, () -> System.out.println("任务3开始"), executor);
// CompletableFuture<Void> future3 = future1.thenAcceptBothAsync(future2, (f1, f2) -> {
// System.out.println("任务3开始 得到f1:" + f1 + " f2:" + f2);
// }, executor);
// CompletableFuture<String> future3 = future1.thenCombineAsync(future2, (f1, f2) -> {
// System.out.println("任务3开始 得到f1:" + f1 + " f2:" + f2);
// return "f3=" + f1 + "," + f2;
// }, executor);
// String s = future3.get();
/**
* 两个任务只要有一个完成就执行...
* 1),runAfterEitherAsync:不感知结果 自己也无返回值
* 2),acceptEitherAsync: 可以感知结果 自己无返回值
* 3),applyToEitherAsync: 可感知结果 有返回值
*/
// future1.runAfterEitherAsync(future2,()->{
// System.out.println("任务3开始");
// },executor);
// future1.acceptEitherAsync(future2,(res)->{
// System.out.println("任务3开始 future1结果:"+res);
// },executor);
// CompletableFuture<String> future3 = future1.applyToEitherAsync(future2, (res) -> res.toString() + "任务3结果", executor);
// String s = future3.get();
/**
* 多任务组合 (项目常用)
* CompletableFuture<Void> allOf = CompletableFuture.allOf(future1, future2, future3);
* allOf.get();//等待所有的都完成
*/
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品图片信息");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("查询商品图片信息end");
return "hello.jpg";
}, executor);
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品属性");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("查询商品属性end");
return "黑色+256g";
}, executor);
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品介绍");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("查询商品介绍end");
return "华为";
}, executor);
// CompletableFuture<Void> allOf = CompletableFuture.allOf(future1, future2, future3);
// allOf.get();//等待所有的都完成
CompletableFuture<Object> anyOf = CompletableFuture.anyOf(future1, future2, future3);
anyOf.get();//
System.out.println("-----------------main----end--------------"+anyOf.get());
}
}
多线程好处:
多线程编码有许多好处,特别是在需要同时执行多个任务或处理大量并发请求的情况下。以下是一些多线程编码的好处:
-
提高性能: 多线程允许程序同时执行多个任务,从而可以更充分地利用多核处理器和计算资源。这可以显著提高程序的执行速度和响应时间。
-
并发处理: 多线程允许程序同时处理多个并发请求。例如,一个网络服务器可以使用多线程来同时处理多个客户端请求,从而提高系统的并发处理能力。
-
响应性: 在图形用户界面(GUI)应用程序中,使用多线程可以确保用户界面的响应性。主线程负责处理用户输入和界面更新,而后台线程可以执行耗时的任务,使界面保持流畅响应。
-
资源共享: 多线程允许线程之间共享同一个进程内的资源,如内存和文件。这可以减少资源的浪费,提高资源利用率。
-
模块化设计: 使用多线程可以将程序分解为更小的模块,每个模块可以在独立的线程中执行。这种模块化设计可以提高代码的可维护性和可扩展性。
-
复杂任务分解: 将复杂的任务分解为多个线程可以简化问题的解决过程。每个线程负责处理一部分任务,从而使问题更容易管理和调试。
-
并行计算: 对于需要进行大规模计算或数据处理的应用程序,多线程可以实现并行计算,将任务分发给多个线程同时执行,从而加速计算过程。
-
实时应用: 在需要实时响应的应用程序中,多线程可以确保任务在规定的时间内得到执行,满足实时性要求。
尽管多线程编码带来了许多好处,但也需要小心处理线程同步、竞态条件等并发编程中的问题。不当的多线程设计可能导致死锁、资源争用等问题,因此在进行多线程编码时需要仔细考虑和规划。