Java for循环+多线程+回调

1.问题背景

因为线上数据库存储过程在执行 “一次性大批量提交” 时失败,在无法升级数据库服务器的情况下,只能将一次大批量的提交任务进行分割,并且等待所有的分割任务都执行结束后再返回具体执行结果(此处也可以不返回,异步操作分割及调用数据库,因为可能有时候执行的时间较长,用户等待时间长、体验差);
具体的业务代码不方便展示,此处就将这部分内容简单展现,做一个小demo。

2.解决方案

/**
     * main  :   多线程+for循环+回调 测试demo
     *
     * @param args
     * @return void
     * @Author wanglx
     * @Date 2023/3/10 16:01
     */
    public static void main(String[] args) {
        //1.定义测试数据
        List<Integer> submitTestList = new ArrayList<>();
        int submitMaxCount = 300;
        for (int i=1;i<=12345;i++){
            submitTestList.add(i);
        }

        //2.定义分割数字段
        int beginInt;
        int endInt;
        int total = submitTestList.size();
        int forCountOne = total % submitMaxCount;
        int forCountTwo = total / submitMaxCount;
        if (forCountOne != 0) {
            forCountTwo = forCountTwo + 1;
        }
		//3.定义信号器等所需对象
        CountDownLatch countDownLatch = new CountDownLatch(forCountTwo);
        
        //定义随机数生成对象,此处仅用来模拟线程延迟,真实环境下请视情去除
        Random rand = new Random();
        
        /**
         * 参数信息:
         * int corePoolSize     核心线程大小
         * int maximumPoolSize  线程池最大容量大小
         * long keepAliveTime   线程空闲时,线程存活的时间
         * TimeUnit unit        时间单位
         * BlockingQueue<Runnable> workQueue  任务队列。一个阻塞队列
         */
        ExecutorService executorService = new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>());

		/**
          *此处也可以直接使用谷歌的工具方法来进行分割,但是为了更便于大众理解,此处使用普通for循环来进行操作
          * List<List<Integer>> partition = Lists.partition(submitTestList , submitMaxCount);
          */
        for (int submitCount = 1; ; submitCount++) {
            beginInt = (submitCount - 1) * submitMaxCount;
            endInt = Math.min(submitCount * submitMaxCount, total);
            List<Integer> integers = submitTestList.subList(beginInt, endInt);
            executorService.execute(() -> submitTest(integers, countDownLatch,rand));
            log.info(" 数量 :{},第{}次",integers.size(),submitCount);
            if (submitCount * submitMaxCount > total) {
                try {
                    boolean await = countDownLatch.await(60, TimeUnit.SECONDS);
                    if (!await) {
                        log.info("线程:{},批量提交失败,CountDownLatch 执行超时", Thread.currentThread().getName());
                        break;
                    }
                } catch (InterruptedException e) {
                    log.error("线程:{},批量提交失败,CountDownLatch 执行异常", Thread.currentThread().getName());
                    break;
                }
                log.info("线程:{},批量提交结束,执行完成", Thread.currentThread().getName());
                break;
            }
        }
    }

/**
     * submitTest  :   提交方法(随机数生成和sleep是为了让每个线程都休眠1-3秒,
     * 							营造出批量提交数据时的延时效果,真实场景下当然不会这样啦。。)
     * 					业务逻辑基本上就是写在这个方法中的
     *
     * @param submits 提交内容集合
     * @param countDownLatch 计数器
     * @param rand  随机数生成类
     * @return void 
     * @Author wanglx
     * @Date 2023/3/10 16:16
     */
public static void submitTest(List<Integer> submits, CountDownLatch countDownLatch, Random rand) {
        log.info("多线程提交XXX开始,ThreadName:{}",Thread.currentThread().getName());
        int randNumber = (rand.nextInt(3) + 1) *1000;
        sleep(randNumber);
        log.info("多线程提交XXX结束,submits:{} ,randNumber :{} ", submits ,randNumber);
        //计数-1是为了最终所有的线程任务执行结束后,同上方的 await 方法相呼应,使主线程能够执行下去
        countDownLatch.countDown();
    }

运行结果-一
运行结果-二

运行结果-三

tips:

关于线程池(ThreadPoolExecutor)和信号器或者计数器(CountDownLatch,我习惯叫它信号器)的相关延伸知识,此处不做赘述,想了解的小伙伴们可以自行通过下方链接直达哦!
ThreadPoolExecutor:ThreadPoolExecutor详解
CountDownLatch:CountDownLatch详解

3.总结

本次是因为要处理线上问题才来研究这种线程用法的,通过研究也进一步加深了线程相关的知识,总体来讲算是劳有所得;
工作之后才发现,除非是真的热爱这个行业,否则大多数人终其一生也只是在编码入门线上摩擦,我如今亦如此;
通过写博文,希望可以通过“问题驱动学习”、“分享驱动学习”来督促、激励自已深耕码田。

时刻提醒自身多学习、常进步、稳提升!!!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: 下面是一个 VB6 多线程代码样例: ``` Private Sub Form_Load() Dim Thread1 As New Thread Set Thread1 = New Thread Thread1.ThreadID = 1 Thread1.Run End Sub Private Sub Class_Initialize() Dim Thread2 As New Thread Set Thread2 = New Thread Thread2.ThreadID = 2 Thread2.Run End Sub Private Sub Thread_Run() Dim i As Long For i = 1 To 100 Debug.Print "Thread " & ThreadID & ": " & i Sleep 1000 Next End Sub ``` 这是一个简单的 VB6 多线程程序,它创建了两个线程:一个在 `Form_Load` 事件中创建,另一个在类的初始化中创建。每个线程都在循环中输出其 `ThreadID` 和循环计数器的值,并在每次循环之间使用 `Sleep` 函数暂停一秒。 请注意,由于 VB6 不支持原生多线程,因此上述代码使用类来实现多线程。 ### 回答2: 在VB6中,虽然不支持直接的多线程编程,但可以通过API函数来实现多线程的功能。下面是一个使用VB6编写的多线程代码示例: 首先,在VB6中创建一个新的标准EXE项目。然后在Form1的代码模块中添加以下代码: ```vb Option Explicit Private Declare Function CreateThread Lib "kernel32" ( _ ByVal lpThreadAttributes As Long, _ ByVal dwStackSize As Long, _ ByVal lpStartAddress As Long, _ ByVal lpParameter As Long, _ ByVal dwCreationFlags As Long, _ lpThreadId As Long) As Long Private Declare Function WaitForSingleObject Lib "kernel32" ( _ ByVal hHandle As Long, _ ByVal dwMilliseconds As Long) As Long Private Sub Form_Load() Dim hThread As Long Dim dwThreadId As Long ' 创建一个新线程 hThread = CreateThread(ByVal 0&, 0&, AddressOf ThreadProc, ByVal 0&, 0&, dwThreadId) ' 等待线程结束 WaitForSingleObject hThread, INFINITE ' 关闭线程句柄 CloseHandle hThread ' 显示线程结束提示 MsgBox "线程结束" End Sub Private Sub ThreadProc() ' 在这里编写多线程的代码逻辑 MsgBox "多线程执行" End Sub ``` 在上面的例子中,我们使用了CreateThread和WaitForSingleObject两个API函数来创建和控制线程。在Form_Load事件中,我们通过调用CreateThread函数创建了一个新的线程,并将线程函数指定为ThreadProc。然后使用WaitForSingleObject函数等待线程结束,保证线程的完整执行。最后,我们通过CloseHandle函数关闭线程句柄,清理资源。在ThreadProc函数中,我们可以编写我们需要在新线程中执行的任何代码逻辑。 需要注意的是,由于VB6的单线程限制,无法直接从新线程中访问窗体上的控件,如果需要更新界面的话,可以使用回调函数的方式来通知主线程进行更新。 虽然VB6不是推荐用于多线程编程,但通过API的帮助,我们可以实现简单的多线程功能。 ### 回答3: VB6是一门过时的编程语言,不支持多线程编程。然而,我们可以通过使用ActiveX组件来实现多线程行为。下面是一个简单的VB6多线程代码样例: 首先,我们需要创建一个ActiveX DLL项目。打开VB6,并选择“ActiveX DLL”模板,命名为“MultiThreadDLL”。 在Class1模块中,添加以下代码: ```vb Option Explicit Public Event ThreadCompleted(ByVal result As String) Public Sub StartThread() Dim t As ThreadClass Set t = New ThreadClass Set t.Parent = Me t.StartThread End Sub Public Sub OnThreadCompleted(result As String) RaiseEvent ThreadCompleted(result) End Sub ``` 然后,添加一个标准模块。在模块中添加以下代码: ```vb Option Explicit Dim WithEvents mt As New MultiThreadDLL.Class1 Private Sub mt_ThreadCompleted(ByVal result As String) MsgBox "线程执行完毕,结果为:" & result End Sub Sub StartMultiThread() mt.StartThread End Sub ``` 最后,我们需要创建一个Class模块,命名为“ThreadClass”。在Class模块中添加以下代码: ```vb Option Explicit Public Parent As MultiThreadDLL.Class1 Public Sub StartThread() Dim t As ThreadClass Set t = New ThreadClass t.Parent = Me.Parent Dim result As String '模拟耗时操作 For i = 1 To 100000000 result = result & i Next i Me.Parent.OnThreadCompleted result End Sub ``` 现在,我们可以在标准模块中调用StartMultiThread过程来启动多线程。当线程执行完毕时,会弹出一个消息框显示结果。 需要注意的是,由于VB6不是原生支持多线程编程,所以它的多线程实现仅仅是通过使用ActiveX组件来模拟实现的,并不是真正的多线程。在实际开发中,建议使用支持多线程的现代编程语言,如C#或Java
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

民兵王er蛋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值