精华内容
下载资源
问答
  • 多线程事务处理问题

    千次阅读 2021-02-12 19:06:27
    代码EquipCollectServiceImpl.javaprotected static final ExecutorService handleTaskPoolExecutor = Executors....public void queryDataToUpload(){// 查询待上传信息List list = equipCollectDao.quer...

    代码

    EquipCollectServiceImpl.java

    protected static final ExecutorService handleTaskPoolExecutor = Executors.newFixedThreadPool(3);

    public void queryDataToUpload(){

    // 查询待上传信息

    List list = equipCollectDao.queryDataByParams();

    // 多线程 调用上传接口

    handleTaskPoolExecutor.submit(

    @Override

    new Runnable(){

    public void run(){

    // ... 接口调用 ...

    Json backInfo = {..};

    // 保存接口日志(方式 1) -> 报错

    interfaceDao.insertInterfaceBackLog(backInfo);

    // 保存接口日志(方式 2) -> 2.1报错 2.2成功

    saveInterfaceBackLog(backInfo);

    // 保存接口日志(方式 3) -> 成功

    interfaceService.insertInterfaceBackLog(backInfo);

    }

    }

    );

    }

    @Transactional

    public void saveInterfaceBackLog(Json backInfo){

    // 方式 2.1

    interfaceDao.insertInterfaceBackLog(backInfo);

    // 方式 2.2

    interfaceService.insertInterfaceBackLog(backInfo);

    }

    报错说明

    insertInterfaceBackLog()方法中使用 查询 报:

    java.util.concurrent.ExecutionException: org.hibernate.HibernateException:

    Could not obtain transaction-synchronized Session for current thread

    insertInterfaceBackLog()方法中使用 保存 报:

    org.springframework.dao.InvalidDataAccessApiUsageException:

    Write operations are not allowed in read-only mode (FlushMode.MANUAL):

    Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.

    问题分析

    查询 this.getSessionFactory().getCurrentSession() 获取不到session,然后直接报错;

    保存 this.getSessionFactory().getCurrentSession() 获取不到session,会创建新session,但是FlushMode.MANUAL < FlushMode.COMMIT,然后报错;

    spring-orm-4.3.4.RELEASE.jar源码如下:

    if (session == null) {

    session = this.getSessionFactory().openSession();

    session.setFlushMode(FlushMode.MANUAL);

    isNew = true;

    }

    总结

    多线程内部不被事务控制,获取不到session,但是能够获取spring注入的bean;

    多线程内部执行同类中方法,不会分配新事务(注解,AOP切面 均不生效);

    方式 3,方式 2.2 每执行一次就会启动一个事务;不会影响到同线程的其他事务;

    展开全文
  • java使用多线程查询大批量数据

    千次阅读 2021-03-08 08:59:40
    前言在某些时候,一旦单表数据量过大,查询数据的时候就会变得...这个查询的过程,数据量一旦过大,单线程查询数据将会成为瓶颈,下面尝试使用多线程来尝试查询一张数据量较大的表由于代码逻辑不是很难,直接上代码...

    前言

    在某些时候,一旦单表数据量过大,查询数据的时候就会变得异常卡顿,虽然在大多数情况下并不需要查询所有的数据,而是通过分页或缓存的形式去减少或者避免这个问题,但是仍然存在需要这样的场景,比如需要导出一大批数据到excel中,导出数据之前,首先得把数据查询出来吧?这个查询的过程,数据量一旦过大,单线程查询数据将会成为瓶颈,下面尝试使用多线程来尝试查询一张数据量较大的表

    由于代码逻辑不是很难,直接上代码,关键的地方会有代码注释和说明,总体实现思路:

    查询表的数据总量

    线程切分,根据本机CPU的核数配置合适数量的线程处理数,根据数据总量为不同的线程分配不同的查询数据量分段,即不同的线程查询不同分段的数据

    将各个查询数据的线程提交至线程池,这里使用的线程是带有返回结果的异步线程

    1、测试控制器

    @GetMapping("/getSysLogMulti")

    @ApiOperation(value = "多线程获取日志数据", notes = "多线程获取日志数据", produces = "application/json")

    public List getSysLogMulti() {

    return operLogService.getSysLogMulti();

    }

    2、业务实现类

    @Autowired

    private MultiThreadQueryUtil multiThreadQueryUtil;

    @Override

    public ListgetSysLogMulti(){

    return multiThreadQueryUtil.getMultiCombineResult();

    }

    3、多线程实现类

    import com.sx.workflow.mapper.WorkflowTaskMapper;

    import com.sx.workflow.util.ExcelLocalUtils;

    import org.springframework.beans.factory.annotation.Autowired;

    import org.springframework.stereotype.Service;

    import java.util.ArrayList;

    import java.util.List;

    import java.util.Map;

    import java.util.concurrent.Callable;

    import java.util.concurrent.ExecutorService;

    import java.util.concurrent.Executors;

    import java.util.concurrent.Future;

    /**

    * 多线程查询结果

    */

    @Service

    public class MultiThreadQueryUtil {

    @Autowired

    private WorkflowTaskMapper workflowTaskMapper;

    /**

    * 获取多线程结果并进行结果合并

    * @return

    */

    public ListgetMultiCombineResult() {

    //开始时间

    long start = System.currentTimeMillis();

    //返回结果

    Listresult = new ArrayList<>();

    //查询数据库总数量

    int count = workflowTaskMapper.selectCountAll();

    MapsplitMap = ExcelLocalUtils.getSplitMap(count,5);

    int bindex = 1;

    //Callable用于产生结果

    List> tasks = new ArrayList<>();

    for (int i = 1; i <= 5; i++) {

    //不同的线程用户处理不同分段的数据量,这样就达到了平均分摊查询数据的压力

    String[] nums = splitMap.get(String.valueOf(i)).split(":");

    int startNum = Integer.valueOf(nums[0]);

    int endNum = Integer.valueOf(nums[1]);

    Callableqfe = new ThredQuery(startNum, endNum-startNum+1);

    tasks.add(qfe);

    bindex += bindex;

    }

    try{

    //定义固定长度的线程池 防止线程过多,这个数量一般跟自己电脑的CPU核数进行匹配

    ExecutorService executorService = Executors.newFixedThreadPool(5);

    //Future用于获取结果

    List> futures=executorService.invokeAll(tasks);

    //处理线程返回结果

    if(futures!=null&&futures.size() > 0){

    for (Futurefuture:futures){

    result.addAll(future.get());

    }

    }

    //关闭线程池,一定不能忘记

    executorService.shutdown();

    }catch (Exception e){

    e.printStackTrace();

    }

    long end = System.currentTimeMillis();

    System.out.println("线程查询数据用时:"+(end-start)+"ms");

    return result;

    }

    }

    4、不同的线程负责查询自己线程负责的数据分段的数据方法

    public class ThredQuery implements Callable{

    public static SpringContextUtil springContextUtil = new SpringContextUtil();

    private int start;

    private int end;

    //每个线程查询出来的数据集合

    private List datas;

    public ThredQuery(int start,int end) {

    this.start=start;

    this.end=end;

    //每个线程查询出来的数据集合

    WorkflowTaskService workflowTaskService = springContextUtil.getBean("workflowTaskService");

    List count = workflowTaskService.getCurrentTasks(start,end);

    datas = count;

    }

    //返回数据给Future

    @Override

    public List call() throws Exception {

    return datas;

    }

    }

    获取具体的bean的工具类,由于线程中无法注册bean,因此需要通过获取bean的方式来进行数据库查询和交互,代码如下:

    import org.springframework.beans.BeansException;

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.ApplicationContextAware;

    import org.springframework.stereotype.Component;

    @Component("springContextUtil")

    public class SpringContextUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext; // Spring应用上下文环境

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

    SpringContextUtil.applicationContext = applicationContext;

    }

    public static ApplicationContext getApplicationContext() {

    return applicationContext;

    }

    @SuppressWarnings("unchecked")

    public static T getBean(String name) throws BeansException {

    return (T) applicationContext.getBean(name);

    }

    @SuppressWarnings("unchecked")

    public static T getBean(Class> clz) throws BeansException {

    return (T) applicationContext.getBean(clz);

    }

    }

    最后运行一下程序,通过接口来调用一下,通过执行结果可以看到,我这里单表大概5万多条数据,测试了几次,平均下来,不到2秒的时间,总体来说,还是很快的

    831caa666bab3ed81ce817a94990b2f6.png

    本篇内容比较简单,主要是方便后续使用时查阅,希望对看到的同学有用,最后感谢观看!

    展开全文
  • 咨询方法-以多线程不同驱动源执行计划处理查询的方法和系统.zip
  • 多线程处理任务并合并数据

    千次阅读 2018-12-29 17:19:28
    newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待...

    一、线程池创建四种方式

    Java通过Executors提供四种线程池,分别为:
    newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
    newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
    newScheduledThreadPool 创建一个定时线程池,支持定时及周期性任务执行。
    newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

    二、有返回值的多线程

    ExecutorService接口继承自Executor,Executor中的execute方法无返回值,ExecutorService接口中的方法有返回值。

    三、计数器使用

    CountDownLatch也是juc包中的一个类,类似倒计时计数器,创建对象时通过构造方法设置初始值,调用CountDownLatch对象的await()方法则处于等待状态,调用countDown()方法就将计数器减1,当计数到达0时,则所有等待者或单个等待者开始执行。

    有了计数器就可以暂时将主线程阻塞,等异步的多线程全部执行完毕并返回结果后,再继续执行主线程。

    四、线程安全问题

    有了上面线程池跟计数器的基础,现在可以动手写一个多线程处理任务并合并数据的demo了。

    大致思路就是:创建一个定长的线程池,长度为10,计数器初始值也设置为10。每执行一次,将计数器减一,并且将执行结果添加到list集合中,最终多线程全部执行完毕后,计数器停止等待 主线程继续往下执行,返回list。

    public static List<String> getExecutorService() throws InterruptedException{
    		System.out.println("开始执行多线程...");
    		long startTime = System.currentTimeMillis();
    		List<String> list = new ArrayList<>();//存放返回结果
    		CountDownLatch countDownLatch = new CountDownLatch(10);
    		ExecutorService executorService = Executors.newFixedThreadPool(10);
    		for (int i = 0; i < 10; i++) {
    			Runnable runnable = new Runnable(){
    
    				@Override
    				public void run() {
    					 try {
    						Thread.sleep(3000);
                            list.add(UUID.randomUUID().toString());
                            System.out.println("当前线程name : "+Thread.currentThread().getName());
                            countDownLatch.countDown();
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				}
    				
    			};
    			executorService.execute(runnable);
    		}
    		countDownLatch.await();
    		System.out.println("submit总共cost 时间:" + (System.currentTimeMillis()-startTime)/1000 + "秒");
    		executorService.shutdown();
    		return list;
    	}

     执行结果如下:

    十个线程全部工作,但是返回值中却有null值,跟想要的结果有点出入,为啥呢?

    原因在于:ArrayList是非线程安全的。ArrayList的add方法中有size++,不是一个原子操作,所以线程不安全。

     五、CopyOnWriteArrayList的用法

    part4中提到的问题 解决方案很简单,将ArrayList换成CopyOnWriteArrayList即可。

    	public static List<String> getExecutorService() throws InterruptedException{
    		System.out.println("开始执行多线程...");
    		long startTime = System.currentTimeMillis();
    		List<String> list = new CopyOnWriteArrayList<>();//存放返回结果
    		CountDownLatch countDownLatch = new CountDownLatch(10);
    		ExecutorService executorService = Executors.newFixedThreadPool(10);
    		for (int i = 0; i < 10; i++) {
    			Runnable runnable = new Runnable(){
    
    				@Override
    				public void run() {
    					 try {
    						Thread.sleep(3000);
                            list.add(UUID.randomUUID().toString());
                            System.out.println("当前线程name : "+Thread.currentThread().getName());
                            countDownLatch.countDown();
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				}
    				
    			};
    			executorService.execute(runnable);
    		}
    		countDownLatch.await();
    		System.out.println("submit总共cost 时间:" + (System.currentTimeMillis()-startTime)/1000 + "秒");
    		executorService.shutdown();
    		return list;
    	}

     

     CopyOnWriteArrayList是Java并发包中提供的一个并发容器,它是个线程安全且读操作无锁的ArrayList,写操作则通过创建底层数组的新副本来实现,是一种读写分离的并发策略,我们也可以称这种容器为"写时复制器"。

    优点:读操作时性能很高,因为不需要任何同步措施,适用于读多写少的并发场景。

    缺点:①.每次写操作都要copy原容器,频繁的GC,内存压力大。②.由于读写分离的策略,读到的数据很可能是旧数据。

    展开全文
  • 需求中需要查询多个SQL...但是使用并行的方式进行查询,即多线程查询,所消耗的时间为查询最久SQL的时间。 此处使用callable + furtherTask 方式实现 Callable<List<Map<String, String>>> ma...

    需求中需要查询多个SQL结果,且这些结果间没有相互联系。

    正常情况下使用串行的方式进行查询,所消耗的时间为所有SQL查询的时间之和,

    但是使用并行的方式进行查询,即多线程查询,所消耗的时间为查询最久SQL的时间。

    此处使用callable + furtherTask 方式实现

    Callable<List<Map<String, String>>> mainCall = new Callable<List<Map<String, String>>>(){
    	@Override
    	public List<Map<String, String>> call() throws Exception {
    		//创建DBConnection,可以创建在外部,但需要使用final关键字
    		DBConnection dbc = DataSource.getDBConnection("odsm");
    		//平台封装方法,创建查询,此处注意需要每次new一个DBQuery,否则仍然是串行执行,
            //猜测一个DBQuery同一时间只能执行一个查询,此处DBQuery仅针对我个人使用的平台。
    		DBQuery dbq = new DBQuery(dbc);
    		//查询结果存储在list内
    		List<Map<String, String>> list = dbq.query("TEMP_WY.queryMain", map);
    		//返回查询结果
    		return list;
    	}
    };

    创建一个FutureTask用于存放查询后的结果,在Thread执行后通过get获取

    FutureTask<List<Map<String, String>>> mainFuture = new FutureTask<List<Map<String, String>>>(mainCall);
    new Thread(mainFuture).start();
    //FutureTask的get方法是线程阻塞的,必须要等待线程都执行完成后,才能获取到结果
    List<Map<String, String>> mainList = mainFuture.get();

    以上是一个线程的创建、执行、获取方法。

    多个线程即重复以上定义即可。

    另外建议根据SQL查询来放置线程顺序,我有两个线程都涉及复杂的查询,且用到同几个表:关联、子查询、汇总等,原来将两个放在7与8的位置,导致同一时间同一资源占用较大,通常第8个查询需要20s才能让出结果,将两个一个放在第一个线程执行,一个放在最后一个线程执行,虽然是并发执行,但执行速度明显加快。

    展开全文
  • 对于复杂的业务sql查询,可以...3.在2的步骤中,可以使用多线程处理for查询。 可以参考如下: 其中&nbsp;conList 是查询主表返回的list //线程池初始化 ThreadPoolExecutor executor = ThreadPool.getThreadPoo...
  • 我用的存储引擎是MyISAM,有个连接会同时select这张表,但不会修改这张表,这样操作会不会有冲突,会不会锁表? 不会锁表,不会有冲突, MyISAM表的读操作,不会阻塞其他用户对同一表的读请求,但会阻塞对同一表...
  • 使用并发包中的Callable及Future类处理。 话不多少,直接上代码: import lombok.extern.slf4j.Slf4j; import java.util.concurrent.Callable; /** * @Author: lp * @Date: 2019- */ @Slf4j public class ...
  • java多线程异步实例

    2012-11-19 11:17:28
    java线程异步案例,以三个线程作为案例典型,同时发起三个线程,根据不同的订单领取各自的物品,自作过程同步处理
  • 1.利用redis特性保证多线程环境下分页查询不出错 2.通过redis保证了数据的读写效率,并将数据通过第三方缓存,方便进行多机部署,使服务灵活扩展性大大提高,读取慢就多架设producer,处理慢就多架设consumer 3.充分利用...
  • linux多线程信号处理

    千次阅读 2016-07-04 20:28:50
    在linux下,每个进程都有自己的signal mask,这个信号掩码指定哪个信号被阻塞,哪个不会...使用了多线程后,便有些疑问: 信号发生时,哪个线程会收到 是不是每个线程都有自己的mask及action 每个线程能按自己的方
  • 1.在已有的spring+mybatis项目中增加了多线程访问数据库的业务,主要是查询,添加,写入到其它数据源。 2.部分需要支持多线程的service类已增加@scope("prototype"),从debug可以看到service获取到的已是不同的对象...
  • 大数据量处理多线程和高并发的问题一直是Java技术面试中比较喜欢问的问题之一,遂在此做个总结 一、数据量太大获取缓慢怎么办? 貌似这个问题在所有开发的应用系统中都会碰到这个问题,随着时间的推移,由于需求...
  • Android多线程(Handler篇)

    万次阅读 多人点赞 2018-06-13 23:09:01
    由于Android中的耗时操作不能放入主线程中,所以实现多线程是必须的。今天的主角是Handler,本文将从使用及源码来分析探索其奥秘。 使用 步骤: 创建Handler对象,实现handlMessage()方法 创建...
  • Java:多线程:到底什么时候该用多线程

    万次阅读 多人点赞 2018-09-30 16:27:29
    系统接受实现多用户多请求的高并发时,通过多线程来实现。   二、线程后台处理大任务 一个程序是线性执行的。如果程序执行到要花大量时间处理的任务时,那主程序就得等待其执行完才能继续执行下面的...
  • java多线程读取多个文件 导入数据库

    万次阅读 2016-10-14 16:59:21
    近期在做java读文件的项目,由于数据量较大,因此研究了一下多线程,总结了一下:一. 多个线程读文件和单个线程读文件,效率差不多,甚至可能不如单线程,原因如下:如果只是单纯的读文件,一个线程足够了,因为一般...
  • 深入了解多线程的原理

    万次阅读 多人点赞 2018-05-25 15:35:48
    即便不考虑多核心,在单核下,多线程也是有意义的,因为在一些操作,比如IO操作阻塞的时候,是不需要CPU参与的,这时候CPU就可以另开一个线程去做别的事情,等待IO操作完成再回到之前的线程继续执行即可 为什么...
  • 系统接受实现多用户多请求的高并发时,通过多线程来实现。 二、线程后台处理大任务 一个程序是线性执行的。如果程序执行到要花大量时间处理的任务时,那主程序就得等待其执行完才能继续执行下面的。那用户就不得...
  • QT多线程编程详解

    万次阅读 多人点赞 2019-04-24 22:08:20
    一、线程基础 1、GUI线程与工作线程 每个程序启动后拥有的第一个线程称为主线程,即GUI线程。QT中所有的组件类和几个相关的类只能工作在GUI线程,不能工作在次...二、QT多线程简介 QT通过三种形式提供了对线程...
  • C# 多线程

    万次阅读 多人点赞 2019-05-29 17:56:35
    一、基本概念 1、进程 首先打开任务管理器,查看当前运行的进程: 从任务管理器里面可以看到当前所有正在运行的进程。...线程是操作系统分配处理器时间的基本单元,在进程中可以有线程同时执行代码。进...
  • python爬虫之多线程、多进程爬虫

    万次阅读 多人点赞 2019-05-09 17:22:00
    多线程对爬虫的效率提高是非凡的,当我们使用python的多线程有几点是需要我们知道的: 1.Python的多线程并不如java的多线程,其差异在于当python解释器开始执行任务时,受制于GIL(全局解释所),Python 的线程被限制...
  • 多线程并发和并行的区别

    千次阅读 2020-09-13 14:35:34
     随着jdk1.8的普及,多线程处理问题,除了使用使用线程池(ExecutorService),很多人选择了parallelStream() 并行流,底层使用forkjoin实现并行处理。  那么并行和并发又有什么区别?究竟改如何选择?滥用时又会有...
  • 多线程线程数设置多少合适

    千次阅读 2020-06-30 01:15:04
    前沿 大家都用过线程池,但是线程池数量设置为多少比较合理呢? 线程数的设置的最主要的目的是为了充分并合理地使用 CPU 和内存等资源,从而...如果有两个任务需要处理,一个任务A,一个任务B 方案一:一个线程执行任务
  • 线程池的配置与并发优化处理,SQL优化性能的一些心得
  • Python多线程编程

    千次阅读 多人点赞 2019-02-28 11:46:07
    多线程(multithreaded, MT)编程出现之前,计算机程序的执行是由单个步骤序列组成的,该序列在主机的 CPU 中按照同步顺序执行。无论是任务本身需要按照步骤顺序执行,还是整个程序实际上包含多个子任务,都需要...
  • Redis到底是单线程还是多线程

    千次阅读 2020-05-18 15:28:54
    这个数据不比采用单进程多线程的同样基于内存的 KV 数据库 Memcached 差!有兴趣的可以参考官方的基准程序测试《How fast is Redis?》(https://redis.io/topics/benchmarks) 横轴是连接数,纵轴是QPS。 此时,这...
  • Java 多线程NIO

    千次阅读 2018-07-04 21:12:12
    IO模型 1. 阻塞IO如果数据没有...3. 路复用IO NIO路复用IO,会有一个线程不断地去轮询个socket的状态,当socket有读写事件的时候才会调用IO读写操作。用一个线程管理个socket,是通过selector.select(...
  • JAVA多线程和线程池

    千次阅读 2019-08-25 11:06:12
    1、线程状态 (1) 新建状态 (2) 就绪状态 (3) 运行状态 (4) 阻塞状态 (5) 死亡状态 2、线程优先级 3、同步工具synchronized、wait、notify 4、创建线程 (1) 实现 Runnable 接口 (2) 继承 Thread 类 (3) ...
  • Qt 多线程详解 - 两种线程使用方式

    千次阅读 2020-05-09 15:11:27
    例如,网络应用程序中,可以使用线程处理多种连接器。 QThread继承自QObject类,且提供QMutex类以实现同步。线程和进程共享全局变量,可以使用互斥体对改变后的全局变量值实现同步。因此,必须编辑全局数据时,使用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 278,665
精华内容 111,466
关键字:

多线程处理不同的查询

友情链接: WinMain.rar