色空大师 2024-09-04 15:30 采纳率: 40.9%
浏览 4

多线程多步骤时未全部完成

跑线程为什么只打印一条信息
代码如下

package com.test.pool.config;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;

import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Configuration
public class ThreadConfig {

    @Qualifier("simpleExecutor")
    @Bean
    public ThreadPoolExecutor simpleExecutor() {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(16,
                16,
                10,
                TimeUnit.MINUTES,
                new SynchronousQueue<>(),
                new CustomizableThreadFactory("simple-pool-"),
                new ThreadPoolExecutor.AbortPolicy());
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        return threadPoolExecutor;
    }
}

package com.test.pool.thread;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Slf4j
public class MyThreadTest {

    public void first(){
        log.info("first");
    }

    public void second(){
        log.info("second");
    }

}

package com.test.pool;

import com.test.pool.thread.MyThreadTest;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import java.util.concurrent.ExecutorService;

@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class SimpleThreadTest {

    @Resource
    ExecutorService simpleExecutor;

    @Test
    public void simpleThreadTest(){

        MyThreadTest myThreadTest = new MyThreadTest();
        simpleExecutor.submit(()->{
            log.info("进入simpleThreadTest");
            try {
                Thread.sleep(1000);
                myThreadTest.first();
            }catch (Exception e){
                log.error("sleep error");
            }
            myThreadTest.second();
        });
    }
}


结果如下

img

问题:为什么不打印second?

展开全部

  • 写回答

1条回答 默认 最新

  • 吃不了席 2024-09-04 15:43
    关注

    以下回复参考:皆我百晓生券券喵儿等免费微信小程序作答:

    这个问题是由于Java线程模型(如ThreadPoolExecutor)的设计所导致的。在Spring框架中,我们使用了基于异步的线程池模式,其中线程执行任务,并且任务完成后会返回给调用者。

    当您尝试从一个线程提交另一个线程的任务时,Java线程模型将不会立即处理第二个任务。这是因为Java线程模型遵循原子性、可串行化以及不可中断原则。这意味着一旦线程开始执行某个任务,它将在整个任务结束之前继续运行直到整个任务完成。

    在这个例子中,您试图同时启动两个线程,每个线程都打算执行MyThreadTest中的first()second()方法。然而,由于Java线程模型的限制,这两个任务将被阻塞,直到第一个任务完成才开始执行第二个任务。

    要解决此问题,您可以考虑以下几种方法:

    1. 使用同步工具包(如ConcurrentHashMap),以确保两个任务按顺序执行。
    2. 将两个方法封装在一个类中,使其成为单个任务的一部分,然后在主函数中通过一个锁(如synchronized关键字)控制其执行次序。

    为了更直观地展示如何实现这些更改,我为您提供了以下示例代码:

    import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.Semaphore;
    import java.util.concurrent.atomic.AtomicInteger;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class MyThreadTest {
    
        private final Lock lock = new ReentrantLock();
    
        public void first() throws InterruptedException {
            lock.lock();
            try {
                // ...
            } finally {
                lock.unlock();
            }
        }
    
        public void second() throws InterruptedException {
            lock.lock();
            try {
                // ...
            } finally {
                lock.unlock();
            }
        }
    }
    

    然后,在您的测试类中,您可以使用Map来存储和管理任务:

    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    public class SimpleThreadTest {
    
        private static Map<String, Runnable> tasks = new ConcurrentHashMap<>();
    
        public static void main(String[] args) {
            // ...
    
            // Submit two tasks to the executor service
            submitTask("first", () -> System.out.println("first"));
            submitTask("second", () -> System.out.println("second"));
    
            // Wait for all tasks to complete
            while (!tasks.isEmpty()) {
                try {
                    tasks.values().stream()
                            .filter(Runnable::isInterrupted)
                            .forEach(runnable -> runnable.run());
                } catch (InterruptedException e) {
                    // Handle interruptedException if it occurs
                }
            }
        }
    
        private static void submitTask(String taskName, Runnable task) {
            tasks.put(taskName, task);
        }
    }
    

    这个示例展示了如何使用ConcurrentHashMap来存储任务及其对应的回调函数,然后在主线程中检查所有任务是否已完成。这应该能够解决您遇到的问题。

    展开全部

    评论
    编辑
    预览

    报告相同问题?

    问题事件

    • 创建了问题 9月4日

    悬赏问题

    • ¥15 PADS Logic 原理图
    • ¥15 PADS Logic 图标
    • ¥15 电脑和power bi环境都是英文如何将日期层次结构转换成英文
    • ¥20 气象站点数据求取中~
    • ¥15 如何获取APP内弹出的网址链接
    • ¥15 wifi 图标不见了 不知道怎么办 上不了网 变成小地球了
    手机看
    程序员都在用的中文IT技术交流社区

    程序员都在用的中文IT技术交流社区

    专业的中文 IT 技术社区,与千万技术人共成长

    专业的中文 IT 技术社区,与千万技术人共成长

    关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

    关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

    客服 返回
    顶部