Java中的异步与线程池解读

目录
  • 初始化线程的4种方式
    • 1.继承Thread
    • 2.实现Runnable 接口
    • 3.实现Callable 接口+ FutureTask (可以拿到返回结果,可以处理异常)
    • 4.线程池
  • 创建线程池(ExecutorService)
    • 1.Executors 工具类创建
    • 2.原生方法创建线程池
    • 3.线程池的运行流程 线程池创建
    • 4. 四种常见的线程池
  • 为什么要使用线程池
  • CompletableFuture 异步编排
    • 1.创建异步对象
    • 2.计算完成时(线程执行成功)回调方法
    • 3.handle 方法(可对结果做最后的处理(可处理异常),可改变返回值)
    • 4.线程串行化
    • 5.两任务组合- 都要完成
    • 6.两任务组合- 一个完成
    • 7.多任务组合
  • 整合SpringBoot

初始化线程的4种方式

1.继承Thread

	Thread01 thread01 = new Thread01();
	thread01.start();

    public static  class Thread01 extends Thread{
        @Override
        public void run() {
            System.out.println("当前线程:"+Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果:"+i);
        }
    }

2.实现Runnable 接口

	Runnable01 runnable01 = new Runnable01();
    new Thread(runnable01).start();

    public static class Runnable01 implements Runnable{
        @Override
        public void run() {
            System.out.println("当前线程:"+Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果:"+i);
        }
    }

3.实现Callable 接口+ FutureTask (可以拿到返回结果,可以处理异常)

    Callabel01 callabel01 = new Callabel01();

    FutureTask<Integer> integerFutureTask = new FutureTask<>(callabel01);
    //阻塞等待整个线程执行完成,获取返回结果
    Integer integer = integerFutureTask.get();
    new Thread(integerFutureTask).start();

    public static class Callabel01 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;
        }
    }

在业务代码里面不建议使用以上三种启动线程的方式

4.线程池

应该将所有的多线程异步任务都交给线程池执行,进行有效的资源控制

//当前系统中池只有一两个,每一个异步任务直接提交给线程池,让他自己去执行
ExecutorService service = Executors.newFixedThreadPool(10);
//执行
service.execute(new Runnable01());

区别

1/2两种方式都不能获取返回值

1/2/3都不能达到资源控制的效果

只有4能控制资源,系统性能是稳定的

创建线程池(ExecutorService)

1.Executors 工具类创建

//当前系统中池只有一两个,每一个异步任务直接提交给线程池,让他自己去执行
ExecutorService service = Executors.newFixedThreadPool(10);
//执行
service.execute(new Runnable01());

2.原生方法创建线程池

ThreadPoolExecutor需要传入七大参数

  • corePoolSize 核心线程数【一直存在,除非设置了允许线程超时的设置:allowCoreThreadTimeOut】,保留在池中的线​​程数,线程池创建后好后就准备就绪的线程数,就等待异步任务去执行,new 好了 Thread,等待异步任务
  • maximumPoolSize 池中最大线程数量,控制资源并发
  • keepAliveTime 存活时间,当前正在运行的线程数量,大于核心线程数,就会释放空闲的线程,只要线程空闲大于指定存活时间,释放的线程是指最大的线程数量减去核心线程数,
  • unit 时间单位
  • BlockingQueue workQueue 阻塞队列,如果任务有很多,就会将目前多的队伍放在队列里面,只要有空闲的线程,就会去队列里面取出新的任务继续执行。
  • new LinkedBlockingQueue<>() 默认值是Integer的最大值,会导致内存不够,一定要传入业务定制的大小,可以通过压测得出峰值
  • threadFactory 线程的创建工厂
  • handler 如果队列满了,按照我们指定的拒绝策略拒绝执行任务

3.线程池的运行流程 线程池创建

准备好core 数量的核心线程,准备接受任务新的任务进来,用core 准备好的空闲线程执行。

(1) 、core 满了,就将再进来的任务放入阻塞队列中。空闲的core 就会自己去阻塞队列获取任务执行

(2) 、阻塞队列满了,就直接开新线程执行,最大只能开到max 指定的数量

(3) 、max 都执行好了。Max-core 数量空闲的线程会在keepAliveTime 指定的时间后自动销毁。最终保持到core 大小

(4) 、如果线程数开到了max 的数量,还有新任务进来,就会使用reject 指定的拒绝策略进行处理所有的线程创建都是由指定的factory 创建的。

一个线程池core 7; max 20 ,queue:50,100 并发进来怎么分配的;先有7 个能直接得到执行,接下来50 个进入队列排队,在多开13 个继续执行。

现在70 个被安排上了。剩下30 个默认拒绝策略。拒绝策略一般是抛弃,如果不想抛弃还要执行,可以使用同步的方式执行,或者丢弃最老的

4. 四种常见的线程池

  • newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。核心线程固定是0,所有都可回收
  • newFixedThreadPool创建一个固定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。固定大小,核心 = 最大
  • newScheduledThreadPool创建一个固定长线程池,支持定时及周期性任务执行。定时任务线程池
  • newSingleThreadExecutor创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。后台从队列里面获取任务 挨个执行

为什么要使用线程池

降低资源的消耗

通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗

提高响应速度

因为线程池中的线程数没有超过线程池的最大上限时,有的线程处于等待分配任务的状态,当任务来时无需创建新的线程就能执行

提高线程的可管理性

线程池会根据当前系统特点对池内的线程进行优化处理,减少创建和销毁线程带来的系统开销。无限的创建和销毁线程不仅消耗系统资源,还降低系统的稳定性,使用线程池进行统一分配

CompletableFuture 异步编排

业务场景:

查询商品详情页的逻辑比较复杂,有些数据还需要远程调用,必然需要花费更多的时间

假如商品详情页的每个查询,需要如下标注的时间才能完成那么,用户需要5.5s 后才能看到商品详情页的内容。很显然是不能接受的。

如果有多个线程同时完成这6 步操作,也许只需要1.5s 即可完成响应。

CompletableFuture 和FutureTask 同属于Future 接口的实现类,都可以获取线程的执行结果。

1.创建异步对象

1、runXxxx 都是没有返回结果的,supplyXxx 都是可以获取返回结果的

2、可以传入自定义的线程池,否则就用默认的线程池;

没有返回结果的

static ExecutorService service = Executors.newFixedThreadPool(10);
CompletableFuture.runAsync(()->{
     System.out.println("当前线程:"+Thread.currentThread().getId());
     int i = 10 / 2;
     System.out.println("运行结果:"+i);
 },service);

有返回结果的

static ExecutorService service = Executors.newFixedThreadPool(10);
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
	 System.out.println("当前线程:" + Thread.currentThread().getId());
	 int i = 10 / 2;
	 System.out.println("运行结果:" + i);
	 return i;
}, service);
	Integer integer = future.get();
	System.out.println("main----end"+integer);

2.计算完成时(线程执行成功)回调方法

whenComplete 可以处理正常和异常的计算结果,虽然可以得到异常信息,但是不能修改返回数据exceptionally 处理异常情况。

可以感知异常并返回默认值whenComplete 和whenCompleteAsync 的区别:

  • whenComplete:是执行当前任务的线程执行继续执行whenComplete 的任务。
  • whenCompleteAsync:是执行把whenCompleteAsync 这个任务继续提交给线程池来进行执行。

方法不以Async 结尾,意味着Action 使用相同的线程执行,而Async 可能会使用其他线程执行(如果是使用相同的线程池,也可能会被同一个线程选中执行)

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main----start");
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 0;
            System.out.println("运行结果:" + i);
            return i;
        }, service).whenComplete((res,excption)->{
            System.out.println("异步任务成功完成:结果是::::"+res+"异常是:"+excption);
        }).exceptionally(throwable->{
            //可以感知异常,同时返回数据
            return 10;
        });
        Integer integer = future.get();
        System.out.println("main----end"+integer);
    }

3.handle 方法(可对结果做最后的处理(可处理异常),可改变返回值)

和complete 一样,可对结果做最后的处理(可处理异常),可改变返回值。

        /* 方法完成后的处理*/
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("运行结果:" + i);
            return i;
        }, service).handle((res,exption)->{
            if (res != null){
                return res*2;
            }
            if (exption != null){
                return 0;
            }
            return 0;
        });

4.线程串行化

  • thenApply 方法:当一个线程依赖另一个线程时,获取上一个任务返回的结果,并返回当前任务的返回值。
  • thenAccept 方法:能接收上一步的返回结果,但是不能改变返回值。
  • thenRun 方法:只要上面的任务执行完成,就开始执行thenRun,不能改变返回值带有Async 默认是异步执行的。同之前。

以上都要前置任务成功完成。

Function<? super T,? extends U>

  • T:上一个任务返回结果的类型
  • U:当前任务的返回值类型
  • thenRun 方法:只要上面的任务执行完成,就开始执行thenRun,不能改变返回值
static ExecutorService service = Executors.newFixedThreadPool(10);

CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("运行结果:" + i);
            return i;
        }, service).thenRunAsync(() -> {
            System.out.println("任务2启动了");
        }, service);
  • thenAccept 方法:能接收上一步的返回结果,但是不能改变返回值。
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("运行结果:" + i);
            return i;
        }, service).thenAccept((res)->{
            System.out.println("异步启动了:"+res);
        });
  • thenApplyAsync 技能接收上一步的结果,又能改变返回值
 CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("运行结果:" + i);
            return i;
        }, service);
        future.thenApplyAsync((res) -> {
            System.out.println("任务2启动了:" + res);
            return res + "hello";
        }, service);

        System.out.println("main----end"+future.get());

5.两任务组合- 都要完成

两个任务必须都完成,触发该任务。

  • thenCombine:组合两个future,获取两个future 的返回结果,并返回当前任务的返回值
  • thenAcceptBoth:组合两个future,获取两个future 任务的返回结果,然后处理任务,没有返回值。
CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("任务1运行结果:" + i);
            return i;
        }, service);

        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2线程:" + Thread.currentThread().getId());
            System.out.println("任务2运行结果:");
            return "hello";
        }, service);

        future01.thenAcceptBothAsync(future02, (f1, f2) -> {
            System.out.println("任务3开始之前的结果---f1=" + f1 + "f2=" + f2);
        }, service);
  • runAfterBoth:组合两个future,不获取前两个的结果,只需两个future 处理完任务后,处理该任务。
        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("任务1运行结果:" + i);
            return i;
        }, service);

        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2线程:" + Thread.currentThread().getId());
            System.out.println("任务2运行结果:");
            return "hello";
        }, service);

        future01.runAfterBothAsync(future02,()->{
            System.out.println("任务3开始");
        },service);

6.两任务组合- 一个完成

当两个任务中,任意一个future 任务完成的时候,执行任务。

  • applyToEither:两个任务有一个执行完成,获取它的返回值,处理任务并自己有新的返回值。
        CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("任务1运行结果:" + i);
            return i;
        }, service);

        CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2线程:" + Thread.currentThread().getId());
            System.out.println("任务2运行结果:");
            return "hello";
        }, service);

        future01.applyToEitherAsync(future02,(t) -> {
            System.out.println("任务3开始"+t);
            return t.toString() + "niubi";
        }, service);
  • acceptEither:两个任务有一个执行完成,获取它的返回值,处理任务,自己没有新的返回值。
 CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("任务1运行结果:" + i);
            return i;
        }, service);

        CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2线程:" + Thread.currentThread().getId());
            System.out.println("任务2运行结果:");
            return "hello";
        }, service);

        future01.acceptEitherAsync(future02,(t) -> {
            System.out.println("任务3开始"+t);
        }, service);
  • runAfterEither:两个任务有一个执行完成,不获取future 的结果,处理任务,自己也没有返回值。
CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("任务1运行结果:" + i);
            return i;
        }, service);

        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2线程:" + Thread.currentThread().getId());
            System.out.println("任务2运行结果:");
            return "hello";
        }, service);

        future01.runAfterEitherAsync(future02,() -> {
            System.out.println("任务3开始");
        }, service);

7.多任务组合

  • allOf:等待所有任务完成
CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的图片信息");
            return "hello.png";
        }, service);
        CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的属性");
            return "黑色+256g";
        }, service);
        CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的介绍");
            return "华为";
        }, service);

        CompletableFuture<Void> completableFuture = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
        completableFuture.get(); //等待所有结果完成
  • anyOf:只要有一个任务完成

整合SpringBoot

1.添加配置类,新建线程池

package cn.cloud.xmall.product.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @Description: ···
 * @author: Freedom
 * @QQ: 1556507698
 * @date:2022/3/21 17:41
 */
@Configuration
public class MyThreadConfig {

    @Bean
    public ThreadPoolExecutor threadPoolExecutor(){
       return new ThreadPoolExecutor(
                20,
                200,
                10,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(100000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
                );
    };
}

2.想要在配置文件中手动的配置参数

新建一个配置属性类

package cn.cloud.xmall.product.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

/**
 * @Description: ···
 * @author: Freedom
 * @QQ: 1556507698
 * @date:2022/3/21 17:47
 */
@ConfigurationProperties(prefix = "xmall.thread")
@Component  //加入容器
@Data
public class ThreadPollConfigProperties {
    private Integer coreSize;
    private Integer maxSize;
    private Integer keepAliveTime;
}

注:可以在依赖种添加此依赖,在配置文件中就会有我们自己配置属性的提示

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-configuration-processor</artifactId>
      <optional>true</optional>
  </dependency>

3.配置文件配置属性

#线程池配置
xmall:
  thread:
    core-size: 20
    max-size: 200
    keep-alive-time: 10

4.使用配置文件中的属性

@EnableConfigurationProperties(ThreadPollConfigProperties.class),如果配置文件类没有添加@Component加入容器可以使用这种方式

package cn.cloud.xmall.product.config;

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @Description: ···
 * @author: Freedom
 * @QQ: 1556507698
 * @date:2022/3/21 17:41
 */
//@EnableConfigurationProperties(ThreadPollConfigProperties.class)
@Configuration
public class MyThreadConfig {

    @Bean
    public ThreadPoolExecutor threadPoolExecutor(ThreadPollConfigProperties pool){
       return new ThreadPoolExecutor(
                pool.getCoreSize(),
                pool.getMaxSize(),
                pool.getKeepAliveTime(),
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(100000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
                );
    };
}

5.注入线程池

    @Autowired
    private ThreadPoolExecutor executor;

6.异步编排

    @Override
    public SkuItemVo item(Long skuId) throws ExecutionException, InterruptedException {

        SkuItemVo skuItemVo = new SkuItemVo();

        //1.使用自己的线程池来新建异步任务
        CompletableFuture<SkuInfoEntity> infoFuture = CompletableFuture.supplyAsync(() -> {
            //1.查询基本信息 pms_sku_info
            SkuInfoEntity info = getById(skuId);
            skuItemVo.setInfo(info);
            return info;
        }, executor);

        //2.根据一号任务来继续调用
        CompletableFuture<Void> saleAttrFuture = infoFuture.thenAcceptAsync((res) -> {
            //3.获取当前spu的销售属性组合
            List<SkuItemSaleAttrVo> saleAttrVos = saleAttrValueService.getSaleAttrsBySpuId(res.getSpuId());
            skuItemVo.setSaleAttr(saleAttrVos);
        }, executor);

        //3.根据一号任务来继续调用
        CompletableFuture<Void> descFuture = infoFuture.thenAcceptAsync((res) -> {
            //4.获取Spu的介绍 pms_spu_info_desc
            SpuInfoDescEntity spuInfo = spuInfoDescService.getById(res.getSpuId());
            skuItemVo.setDesc(spuInfo);
        }, executor);

        //4.根据一号任务来继续调用
        CompletableFuture<Void> baseAttrFuture = infoFuture.thenAcceptAsync((res) -> {
            //5.获取spu的规格参数信息
            List<SpuItemAttrGroupVo> attrGroups = attrGroupService.getAttrGroupWithAttrsBySpuId(res.getSpuId(), res.getCatalogId());
            skuItemVo.setGroupAttrs(attrGroups);
        }, executor);

        //此任务不需要根据一号任务的返回调用,所以开一个新线程
        CompletableFuture<Void> imagesFuture = CompletableFuture.runAsync(() -> {
            //2.获取sku的图片信息 pms_sku_images
            List<SkuImagesEntity> images = imagesService.getImagesBySkuId(skuId);
            skuItemVo.setImages(images);
        }, executor);

        //等待所有任务都完成
        //TODO 可以选择有异常情况下的处理结果
        CompletableFuture.allOf(saleAttrFuture,descFuture,baseAttrFuture,imagesFuture).get();        

        return skuItemVo;
    }

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Java ExecutorServic线程池异步实现流程

    相信大家都在项目中遇到过这样的情况,前台需要快速的显示,后台还需要做一个很大的逻辑.比如:前台点击数据导入按钮,按钮后的服务端执行逻辑A,和逻辑B(执行大量的表数据之间的copy功能),而这时前台不能一直等着,要返回给前台,告诉正在处理中就行了.这里就需要用到异步了. 点击按钮 -> 逻辑A ->逻辑B(异步) -> 方法结束. 到底,项目需求明确了,就引入了ExecutorServic线程池. Java通过Executors提供四种线程池,分别为: newCachedThreadPoo

  • java中常见的6种线程池示例详解

    之前我们介绍了线程池的四种拒绝策略,了解了线程池参数的含义,那么今天我们来聊聊Java 中常见的几种线程池,以及在jdk7 加入的 ForkJoin 新型线程池 首先我们列出Java 中的六种线程池如下 线程池名称 描述 FixedThreadPool 核心线程数与最大线程数相同 SingleThreadExecutor 一个线程的线程池 CachedThreadPool 核心线程为0,最大线程数为Integer. MAX_VALUE ScheduledThreadPool 指定核心线程数的定时

  • Spring Boot使用Spring的异步线程池的实现

    前言 线程池,从名字上来看,就是一个保存线程的"池子",凡事都有其道理,那线程池的好处在哪里呢? 我们要让计算机为我们干一些活,其实都是在使用线程,使用方法就是new一个Runnable接口或者新建一个子类,继承于Thread类,这就会涉及到线程对象的创建与销毁,这两个操作无疑是耗费我们系统处理器资源的,那如何解决这个问题呢? 线程池其实就是为了解决这个问题而生的. 线程池提供了处理系统性能和大用户量请求之间的矛盾的方法,通过对多个任务重用已经存在的线程对象,降低了对线程对象创建和销毁

  • 详解Java中CountDownLatch异步转同步工具类

    使用场景 由于公司业务需求,需要对接socket.MQTT等消息队列. 众所周知 socket 是双向通信,socket的回复是人为定义的,客户端推送消息给服务端,服务端的回复是两条线.无法像http请求有回复. 下发指令给硬件时,需要校验此次数据下发是否成功. 用户体验而言,点击按钮就要知道此次的下发成功或失败. 如上图模型, 第一种方案使用Tread.sleep 优点:占用资源小,放弃当前cpu资源 缺点: 回复速度快,休眠时间过长,仍然需要等待休眠结束才能返回,响应速度是固定的,无法及时响

  • 关于java中@Async异步调用详细解析附代码

    目录 前言 1. @Async讲解 2. 用法 2.1 同步调用 2.2 异步调用 3. 自定义线程池 前言 异步调用与同步调用 同步调用:顺序执行,通过调用返回结果再次执行下一个调用 异步调用:通过调用,无需等待返回结果,执行下一个调用 1. @Async讲解 其@Async的注解代码如下: @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public

  • 浅谈java常用的几种线程池比较

    1. 为什么使用线程池 诸如 Web 服务器.数据库服务器.文件服务器或邮件服务器之类的许多服务器应用程序都面向处理来自某些远程来源的大量短小的任务.请求以某种方式到达服务器,这种方式可能是通过网络协议(例如 HTTP.FTP 或 POP).通过 JMS 队列或者可能通过轮询数据库.不管请求如何到达,服务器应用程序中经常出现的情况是:单个任务处理的时间很短而请求的数目却是巨大的. 构建服务器应用程序的一个简单模型是:每当一个请求到达就创建一个新线程,然后在新线程中为请求服务.实际上对于原型开发这

  • java简单实现多线程及线程池实例详解

    本文为大家分享了java多线程的简单实现及线程池实例,供大家参考,具体内容如下 一.多线程的两种实现方式 1.继承Thread类的多线程 /** * 继承Thread类的多线程简单实现 */ public class extThread extends Thread { public void run(){ for(int i=0;i<100;i++){ System.out.println(getName()+"-"+i); } } public static void mai

  • Java并发之串行线程池实例解析

    前言 做Android的这两年时间,通过研究Android源码,也会Java并发处理多线程有了自己的一些理解. 那么问题来了,如何实现一个串行的线程池呢? 思路 何为串行线程池呢? 也就是说,我们的Runnable对象应该有个排队的机制,它们顺序从队列尾部进入,并且从队列头部选择Runnable进行执行. 既然我们有了思路,那我们就考虑一下所需要的数据结构? 既然是从队列尾部插入Runnable对象,从队列头部执行Runnable对象,我们自然需要一个队列.Java的SDK已经给我们提供了很好的

  • Django异步任务线程池实现原理

    这篇文章主要介绍了Django异步任务线程池实现原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 当数据库数据量很大时(百万级),许多批量数据修改请求的响应会非常慢,一些不需要即时响应的任务可以放到后台的异步线程中完成,发起异步任务的请求就可以立即响应 选择用线程池的原因是:线程比进程更为可控.不像子进程,子线程会在所属进程结束时立即结束.线程可共享内存. 请求任务异步处理的原理 使用python manage.py runserver模式启

  • Java多线程常见案例分析线程池与单例模式及阻塞队列

    目录 一.单例模式 1.饿汉模式 2.懒汉模式(单线程) 3.懒汉模式(多线程) 二.阻塞队列 阻塞队列的实现 生产者消费者模型 三.线程池 1.创建线程池的的方法 (1)ThreadPoolExecutor (2)Executors(快捷创建线程池的API) 2.线程池的工作流程 一.单例模式 设计模式:软件设计模式 是一套被反复使用.多数人知晓.经过分类编目.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性.程序的重用性. 单例模式:是设计模式的一种.

  • Java实现手写一个线程池的示例代码

    目录 概述 线程池框架设计 代码实现 阻塞队列的实现 线程池消费端实现 获取任务超时设计 拒绝策略设计 概述 线程池技术想必大家都不陌生把,相信在平时的工作中没有少用,而且这也是面试频率非常高的一个知识点,那么大家知道它的实现原理和细节吗?如果直接去看jdk源码的话,可能有一定的难度,那么我们可以先通过手写一个简单的线程池框架,去掌握线程池的基本原理后,再去看jdk的线程池源码就会相对容易,而且不容易忘记. 线程池框架设计 我们都知道,线程资源的创建和销毁并不是没有代价的,甚至开销是非常高的.同

  • java中volatile不能保证线程安全(实例讲解)

    今天打了打代码研究了一下java的volatile关键字到底能不能保证线程安全,经过实践,volatile是不能保证线程安全的,它只是保证了数据的可见性,不会再缓存,每个线程都是从主存中读到的数据,而不是从缓存中读取的数据,附上代码如下,当synchronized去掉的时候,每个线程的结果是乱的,加上的时候结果才是正确的. /** * * 类简要描述 * * <p> * 类详细描述 * </p> * * @author think * */ public class Volatil

  • Java中几种常用数据库连接池的使用

    一.应用程序直接获取数据库连接的缺点 用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长.假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出.拓机.如下图所示: 二.使用数据库连接池优化程序性能 2.1.数据库连接池的基本概念 数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现的尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性

随机推荐

其他