spring中使用多线程

我们知道创建多线程有两种方式。
1⃣️实现runnable接口
2⃣️继承thread类
但执行多线程前必须要实例化对象,然后调用start方法才能执行。

我们知道spring通过ioc创建实例,对象被动注入到你需要使用的类中,而且,spring创建对象默认是单例的。那么该如何操作呢?

方法很简单:
1⃣️首先我们需要创建自己的线程类,也就是你要并发执行的任务:
就像下面这样:

@Component("oneTask")
@Scope("prototype")
public class OneTask extends Thread {
    private HashMap item;

    public OneTask(HashMap item) {
        this.item = item;
    }

    public void setItem(HashMap item){
        this.item = item;
    }
    public OneTask(){

    }
    public void run(){
            try {
                System.out.println(">>>>"+Thread.currentThread().getName()+",正在执行第"+(time++) +"次");
                HotelBaseInfo hbi = new HotelBaseInfo();
                if(item!=null){
                    System.out.println(item.toString());
                    System.out.println((String)item.get("UpdatedTime"));
                    FileUtil.write(item.toString(),"/Users/D_xiao/工作/java_file_write/thisHotel.txt");
                    hbi.newLoadFromMap(item);
                    /********/
                    HotelBaseInfo oldHbi = (HotelBaseInfo)hotelBaseDao.queryOne("from HotelBaseInfo h where h.hotelId = ?", new Object[]{hbi.getHotelId()});
                    if (oldHbi!=null) {
                        //System.out.println(">>>>>>获取酒店 id: "+oldHbi.getHotelId());
                        // 说明数据库里面有这条数据,现在就是要使用更新时间做一下对比。
                        if (!oldHbi.getUpdatedTime().equals(hbi.getUpdatedTime())) {
                            System.out.println(">>>>>>>>>>>>数据有更新");
                            // 更新时间不一样,说明数据有更新,先删除原来的数据,再换成新的,用事务控制
                            hotelBaseDao.delete(oldHbi);
                            hbi.setId(UUIDTool.getUUID());
                            hotelBaseDao.add(hbi);
                            // 更新此酒店具体信息
                        //  updateDetailInfo(hbi.getHotelId());
                        }
                    }else{
                        System.out.println(">>>>>>>>>没有该酒店,添加新记录,并添加子节点");
                        hbi.setId(UUIDTool.getUUID());
                        hotelBaseDao.add(hbi);
                        updateDetailInfo(hbi.getHotelId());
                    }
                }
            } catch (IllegalArgumentException | IllegalAccessException e) {
                e.printStackTrace();
                System.out.println("==================================================================");
                System.out.println("更新HotelBaseInfo失败!"+e.getMessage());
                System.out.println("==================================================================");
            }
        //}
    }
注意:这里我们写了一个set方法,可以通过set方法,往线程中传递参数!而且这个子线程要有@Scope("prototype")注解,表示该类是多例的!不然实例化对象只会创建一次!

2⃣️然后在我们的主线程类中创建线程池调用线程或直接调用线程。
就像下面这样:

long start=System.currentTimeMillis();
                System.out.println(">>>>>>>>>>开始下载");   
                HashMap m = xmlToDomain
                        .analyseXml(networkUtil.sendGet("http://api.test.lohoo.com/xml/v2.0/hotel/hotellist.xml"));
                HashMap hotelListMap = (HashMap) m.get("Hotels");
                FileUtil.write(hotelListMap.toString(),"/Users/D_xiao/工作/java_file_write/hotelList.txt");
                System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>已下载酒店跟数据");
                ArrayList<HashMap> hotelList = (ArrayList<HashMap>) hotelListMap.get("Hotel");
                System.out.println(">>>>>>>>>>>>>以获取 Hotel根节点");
                ExecutorService pool = Executors.newFixedThreadPool(10);
                int i = 0;
                for (HashMap item : hotelList) {
                        OneTask one = hotelTaskService.getTask();
                        one.setItem(item);
                        pool.execute(one);
                }
                updateGEOInfo();
                pool.shutdown();
                long end=System.currentTimeMillis();

注意这里我们调用线程是自己实现了一个接口去创建对象的,因为,for循环中通过反射每次都创建新的对象,每个对象创建自己的线程执行。
3⃣️下面是获取线程对象的方法:

@Component("hotelTaskService")  
public class HotelTaskServiceImpl {

    public OneTask getTask(){
        ApplicationContext applicationContext = GETApplicationContext.getApplicationContext();
        OneTask oneTask = (OneTask) applicationContext.getBean("oneTask");
        return oneTask; 
    }
}

尤其要注意!线程类一定要是多例的!

另外,如果在线程中执行其他对象中的方法,而且这个对象是单例的,不要忘了加锁标记!否则可能引起并发错误。如果只在线程类中执行或者调用的别的类是多例的,则不需要考虑这个问题。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring 的定时器可以使用多线程来执行定时任务,以提高执行效率。具体实现方式如下: 1. 在定时任务方法上加上 @Async 注解,表示该方法是一个异步方法,可以在另一个线程执行。 2. 在配置类加上 @EnableAsync 注解,启用 Spring 的异步功能。 3. 在定时任务类使用 TaskExecutor 或者 ThreadPoolTaskExecutor 来创建一个线程池,用来执行异步方法。 下面是一个示例代码: ```java @Component public class MyScheduler { @Autowired private TaskExecutor taskExecutor; @Async @Scheduled(cron = "0 0/1 * * * ?") public void doSomething() { taskExecutor.execute(new Runnable() { @Override public void run() { // 执行具体的定时任务代码 } }); } } @Configuration @EnableScheduling @EnableAsync public class MyConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { // 创建线程池 ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(100); executor.setQueueCapacity(1000); executor.setThreadNamePrefix("MyScheduler-"); executor.initialize(); return executor; } } ``` 在上面的代码,@Async 注解表示 doSomething() 方法是一个异步方法,@Scheduled 注解表示该方法是一个定时任务方法,使用 cron 表达式指定定时任务的执行时间。在 doSomething() 方法使用 taskExecutor.execute() 方法来执行具体的定时任务代码,taskExecutor 是在 MyConfig 配置类创建的线程池。通过这种方式,就可以实现 Spring 定时任务的多线程执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值