多线程竞争执行,谁先跑完用谁?

在性能优化中,面对MongoDB联合查询的性能瓶颈,采用竞争式查询策略,即启动两个线程分别执行内部和外部联合查询,以最快完成的查询结果为准。这种方式利用多线程实现时间的最优化,但未能从根本上解决问题,期待MongoDB官方对联合查询性能的提升。欢迎大家提出更好的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       做性能优化时,遇到一些跨不过的坎,如果能够绕过问题本身来解决该问题也是不错的选择。本人在做 MongoDB 联合查询时,遇到了性能瓶颈,使用 MongoDB 内部联合查询时 Mongo竟然不会使用索引,效率低下,不得采用数据库外部联合查询来解决。那么,问题来了,两种方式优势与劣势同样明显,若要同时运用两种查询方式的优势,避其短处,本人采用了竞争式查询。在不同的场景下,两者同时执行,谁最快执行完成,就用谁,保证执行时间最短。这种方式也是典型的用资源或者空间换时间的做法了。

       多线程竞争代码如下:

package com.zhaoxj_2017.tools;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;

public class CompetitiveExecutor {

    @Test
    public void execute() throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();

        long startTime = System.currentTimeMillis();

        List<FutureTask<Integer>> tasks = new ArrayList<>();
        Signal signal = new Signal();
        CompetitiveCallable callable1 = createCompetitiveCallable(signal);
        CompetitiveCallable callable2 = createCompetitiveCallable(signal);
        CompetitiveCallable callable3 = createCompetitiveCallable(signal);
        CompetitiveCallable callable4 = createCompetitiveCallable(signal);

        FutureTask<Integer> task1 = new FutureTask<>(callable1);
        FutureTask<Integer> task2 = new FutureTask<>(callable2);
        FutureTask<Integer> task3 = new FutureTask<>(callable3);
        FutureTask<Integer> task4 = new FutureTask<>(callable4);

        tasks.add(task1);
        tasks.add(task2);
        tasks.add(task3);
        tasks.add(task4);

        callable1.setCompetitors(tasks);
        callable1.setCurrentTask(task1);
        callable2.setCompetitors(tasks);
        callable2.setCurrentTask(task2);
        callable3.setCompetitors(tasks);
        callable3.setCurrentTask(task3);
        callable4.setCompetitors(tasks);
        callable4.setCurrentTask(task4);

        executorService.submit(task1);
        executorService.submit(task2);
        executorService.submit(task3);
        executorService.submit(task4);

        Integer result = -1;

        for (FutureTask<Integer> task : tasks) {
            try {
                result = task.get();
            } catch (Exception e) {
                continue;
            }

            break;
        }

        System.out.println("Result is : " + result);
        System.out.println("Total execution time is " + (System.currentTimeMillis() - startTime));

        TimeUnit.SECONDS.sleep(10);
        executorService.shutdown();
    }

    private CompetitiveCallable createCompetitiveCallable(Signal signal) {
        return new CompetitiveCallable(new Random().nextInt(5) + 2, signal);
    }


    class Signal {
        private boolean state = true;

        synchronized boolean get() {
            if(state) {
                state = false;
                return true;
            }
            return false;
        }
    }

    class CompetitiveCallable implements Callable<Integer> {
        private List<FutureTask<Integer>> competitors = Collections.emptyList();
        private FutureTask currentTask;
        private Signal signal;

        private int randomResource;
        CompetitiveCallable(int randomResource, Signal signal) {
            this.randomResource = randomResource;
            this.signal = signal;
        }
        void setCompetitors(List<FutureTask<Integer>> competitors) {
            this.competitors = new ArrayList<>(competitors);
        }

        void setCurrentTask(FutureTask currentTask) {
            this.currentTask = currentTask;
        }

        @Override
        public Integer call() throws Exception {
            System.out.println(Thread.currentThread().getName() + ": running, need cost " + randomResource);
            TimeUnit.SECONDS.sleep(randomResource);
            System.out.println(Thread.currentThread().getName() + ": completing, and cost " + randomResource);

            if(signal.get()) {
                System.out.println(Thread.currentThread().getName() + ": Obtain final execution rights.");
                competitors.remove(currentTask);
                competitors.forEach(futureTask -> {
                    try {
                        futureTask.cancel(true);
                    } catch (Exception e) {
                        // Ignore.
                    }
                });
            }
            return randomResource;
        }
    }
}

       该方式的执行时间就是执行最快的线程执行所需要的时间,与此同时,未执行完成的线程也会被取消执行。

       通过多种方式竞争,充分利用各种算法的优点,算是勉强解决了本人所遇问题,但是从根本上解决 MongoDB 联合查询的性能问题,仍需要 Mongo 官方继续优化联合查询性能。

       如果大家有更好的解决方案,欢迎交流。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值