Java多线程并发执行demo代码实例

 更新时间:2020年06月28日 10:15:03   作者:ymh  
这篇文章主要介绍了Java多线程并发执行demo代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

主类:MultiThread,执行并发类

package java8test;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * @param <H> 为被处理的数据类型
 * @param <T>返回数据类型
 * 知识点1:X,T为泛型,为什么要用泛型,泛型和Object的区别请看:https://www.cnblogs.com/xiaoxiong2015/p/12705815.html
 */
public abstract class MultiThread<X, T> {

  public static int i = 0;

  // 知识点2:线程池:https://www.cnblogs.com/xiaoxiong2015/p/12706153.html
  private final ExecutorService exec; // 线程池

  // 知识点3:@author Doung Lea 队列:https://www.cnblogs.com/xiaoxiong2015/p/12825636.html
  private final BlockingQueue<Future<T>> queue = new LinkedBlockingQueue<>();

  // 知识点4:计数器,还是并发包大神 @author Doug Lea 编写。是一个原子安全的计数器,可以利用它实现发令枪
  private final CountDownLatch startLock = new CountDownLatch(1); // 启动门,当所有线程就绪时调用countDown

  private final CountDownLatch endLock; // 结束门

  private final List<X> listData;// 被处理的数据

  /**
   * @param list list.size()为多少个线程处理,list里面的H为被处理的数据
   */
  public MultiThread(List<X> list) {
    if (list != null && list.size() > 0) {
      this.listData = list;
      exec = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); // 创建线程池,线程池共有nThread个线程
      endLock = new CountDownLatch(list.size()); // 设置结束门计数器,当一个线程结束时调用countDown
    } else {
      listData = null;
      exec = null;
      endLock = null;
    }
  }

  /**
   * 
   * @return 获取每个线程处理结速的数组
   * @throws InterruptedException
   * @throws ExecutionException
   */
  public List<T> getResult() throws InterruptedException, ExecutionException {

    List<T> resultList = new ArrayList<>();
    if (listData != null && listData.size() > 0) {
      int nThread = listData.size(); // 线程数量
      for (int i = 0; i < nThread; i++) {
        X data = listData.get(i);
        Future<T> future = exec.submit(new Task(i, data) {

          @Override
          public T execute(int currentThread, X data) {

            return outExecute(currentThread, data);
          }
        }); // 将任务提交到线程池
        queue.add(future); // 将Future实例添加至队列
      }
      startLock.countDown(); // 所有任务添加完毕,启动门计数器减1,这时计数器为0,所有添加的任务开始执行
      endLock.await(); // 主线程阻塞,直到所有线程执行完成
      for (Future<T> future : queue) {
        resultList.add(future.get());
      }
      exec.shutdown(); // 关闭线程池
    }
    return resultList;
  }

  /**
   * 每一个线程执行的功能,需要调用者来实现
   * @param currentThread 线程号
   * @param data 每个线程被处理的数据
   * @return T返回对象
   */
  public abstract T outExecute(int currentThread, X data);

  /**
   * 线程类
   */
  private abstract class Task implements Callable<T> {

    private int currentThread;// 当前线程号

    private X data;

    public Task(int currentThread, X data) {
      this.currentThread = currentThread;
      this.data = data;
    }

    @Override
    public T call() throws Exception {

      // startLock.await(); // 线程启动后调用await,当前线程阻塞,只有启动门计数器为0时当前线程才会往下执行
      T t = null;
      try {
        t = execute(currentThread, data);
      } finally {
        endLock.countDown(); // 线程执行完毕,结束门计数器减1
      }
      return t;
    }

    /**
     * 每一个线程执行的功能
     * @param currentThread 线程号
     * @param data 每个线程被处理的数据
     * @return T返回对象
     */
    public abstract T execute(int currentThread, X data);
  }
}

结果类:ResultVO,保存返回结果,根据实际情况替换成自己的

package java8test;
public class ResultVo {
  int i;
  public ResultVo(int i) {
    this.i = i;
  }
  public ResultVo() {
    // TODO Auto-generated constructor stub
  }
}

参数类:ParamVO,传入参数类,根据实际情况替换成自己的

package java8test;

public class ParamVo {

  private int i;

  ParamVo(int i) {
    this.i = i;
  }

  public int getI() {

    return i;
  }

  @Override
  public String toString() {

    return String.valueOf(i) + " " + hashCode();
  }
}

测试类:new两个MultiThread,可以看到MultiThread这个类不存在线程安全问题。

package java8test;

import java.util.ArrayList;
import java.util.List;

public class Test {

  public static void main(String[] args) {

    try {
      List<ParamVo> splitList = new ArrayList<ParamVo>();
      for (int i = 0; i < 100; i++) {
        splitList.add(new ParamVo(i));
      }
      List<ParamVo> splitList1 = new ArrayList<ParamVo>();
      for (int i = 200; i < 300; i++) {
        splitList1.add(new ParamVo(i));
      }
      MultiThread<ParamVo, ResultVo> multiThread = new MultiThread<ParamVo, ResultVo>(splitList) {

        @Override
        public ResultVo outExecute(int currentThread, ParamVo data) {

          System.out.println("当前线程名称:" + Thread.currentThread().getName() + "当前线程号=" + currentThread
              + " data=" + data);
          i--;
          return new ResultVo(data.getI());
        }
      };

      MultiThread<ParamVo, ResultVo> multiThread1 = new MultiThread<ParamVo, ResultVo>(splitList1) {

        @Override
        public ResultVo outExecute(int currentThread, ParamVo data) {

          System.out.println("当前线程名称:" + Thread.currentThread().getName() + "当前线程号=" + currentThread
              + " data=" + data);
          i--;
          return new ResultVo(data.getI());
        }
      };
      List<ResultVo> list = multiThread.getResult();
      List<ResultVo> list1 = multiThread1.getResult();
      // 获取每一批次处理结果
      System.out.println("获取处理结果........................");
      for (ResultVo vo : list) {
        System.out.println(vo.i);
      }
      System.out.println("获取1处理结果........................");
      for (ResultVo vo : list1) {
        System.out.println(vo.i);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

这个类也用在了生产当中,用来并发插入数据。但是事务不能被管控,需要自己保证最终事务一致。需要注意。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • MyBatis学习教程(六)-调用存储过程

    MyBatis学习教程(六)-调用存储过程

    这篇文章主要介绍了MyBatis学习教程(六)-调用存储过程的相关资料,非常不错,具有参考借鉴价值,感兴趣的朋友一起看下吧
    2016-05-05
  • Java使用DateTimeFormatter实现格式化时间

    Java使用DateTimeFormatter实现格式化时间

    这篇文章主要介绍了Java使用DateTimeFormatter实现格式化时间,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-01-01
  • Java命名规范

    Java命名规范

    本文主要介绍了Java命名规范。具有一定的参考价值,下面跟着小编一起来看下吧
    2017-01-01
  • 五种JAVA GUI布局管理的方式

    五种JAVA GUI布局管理的方式

    这篇文章主要介绍了JAVA几种GUI布局管理的相关知识,文中代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-06-06
  • Java 如何优雅的拷贝对象属性

    Java 如何优雅的拷贝对象属性

    这篇文章主要介绍了Java 如何优雅的拷贝对象属性,帮助大家更好的理解和学习Java,感兴趣的朋友可以了解下
    2020-11-11
  • Spring实现Quartz自动配置的方法详解

    Spring实现Quartz自动配置的方法详解

    这篇文章主要介绍了Spring实现Quartz自动配置的方法详解,如果想在应用中使用Quartz任务调度功能,可以通过Spring Boot实现Quartz的自动配置,以下介绍如何开启Quartz自动配置,以及Quartz自动配置的实现过程,需要的朋友可以参考下
    2023-11-11
  • mybatis学习笔记之mybatis注解配置详解

    mybatis学习笔记之mybatis注解配置详解

    本篇文章主要介绍了mybatis学习笔记之mybatis注解配置详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-12-12
  • Junit测试多线程无法得到结果的问题解决

    Junit测试多线程无法得到结果的问题解决

    在测试一个文件转换工具类的时候,发生一个有趣的现象,同样的输入,使用Main函数可以正确解析,得到结果,使用Junit却无法得到结果,神奇的是,即使捕获Throwable,也无法捕获到仍和异常。
    2021-05-05
  • Java中的递增i++与++i的实现原理详解

    Java中的递增i++与++i的实现原理详解

    这篇文章主要介绍了Java中的i++与++i的实现原理详解,在Java中,i++是一种常见的递增操作符,用于将变量i的值增加1,它是一种简洁且方便的方式来实现循环和计数功能,i++可以用于各种情况,本文来看一下其实现原理,需要的朋友可以参考下
    2023-10-10
  • java解析dbf之通过javadbf包生成和读取dbf文件

    java解析dbf之通过javadbf包生成和读取dbf文件

    这篇文章主要介绍了java通过javadbf读取和生成DBF文件的方法,大家参考使用吧
    2014-01-01

最新评论