亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Schedule定時任務在分布式產(chǎn)生的問題詳解

 更新時間:2022年10月19日 08:46:31   作者:寧在春  
這篇文章主要介紹了Schedule定時任務在分布式產(chǎn)生的問題詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

正文

定時任務的實現(xiàn)方式多種多樣,框架也是層出不窮。

本文所談及的是 SpringBoot 本身所帶有的@EnableScheduling 、 @Scheduled實現(xiàn)定時任務的方式。

以及采用這種方式,在分布式調(diào)度中可能會出現(xiàn)的問題,又針對為什么會發(fā)生這種問題?又該如何解決,做出了一些敘述。

為了適合每個階段的讀者,我把前面測試的代碼都貼出來啦~

確保每一步都是有跡可循的,希望大家不要嫌啰嗦,感謝

一、搭建基本環(huán)境

基本依賴

 <parent>
     <artifactId>spring-boot-parent</artifactId>
     <groupId>org.springframework.boot</groupId>
     <version>2.7.2</version>
 </parent>
 <dependencies>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot</artifactId>
     </dependency>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter</artifactId>
     </dependency>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
     </dependency>
     <dependency>
         <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
         </dependency>
  </dependencies>

創(chuàng)建個啟動類及定時任務

 @SpringBootApplication
 public class ApplicationScheduling {
     public static void main(String[] args) {
         SpringApplication.run(ApplicationScheduling.class, args);
     }
 }
 /**
  * @description:
  * @author: Ning Zaichun
  * @date: 2022年09月06日 0:02
  */
 @Slf4j
 @Component
 @EnableScheduling
 public class ScheduleService {
     // 每五秒執(zhí)行一次,cron的表達式就不再多說明了
     @Scheduled(cron = "0/5 * * * * ? ")
     public void testSchedule() {
             log.info("當前執(zhí)行任務的線程號ID===>{}", Thread.currentThread().getId());
     }
 }

二、問題::執(zhí)行時間延遲和單線程執(zhí)行

按照上面代碼中給定的cron表達式@Scheduled(cron = "0/5 * * * * ? ")每五秒執(zhí)行一次,那么最近五次的執(zhí)行結(jié)果應當為:

 2022-09-06 00:21:10
 2022-09-06 00:21:15
 2022-09-06 00:21:20
 2022-09-06 00:21:25
 2022-09-06 00:21:30

如果定時任務中是執(zhí)行非常快的任務的,時間非常非常短,確實不會有什么的延遲性。

上面代碼執(zhí)行結(jié)果:

 2022-09-06 19:42:10.018  INFO 24496 --- [   scheduling-1] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>64
 2022-09-06 19:42:15.015  INFO 24496 --- [   scheduling-1] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>64
 2022-09-06 19:42:20.001  INFO 24496 --- [   scheduling-1] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>64
 2022-09-06 19:42:25.005  INFO 24496 --- [   scheduling-1] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>64
 2022-09-06 19:42:30.007  INFO 24496 --- [   scheduling-1] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>64

如果說從時間上來看,說不上什么延遲性,但真實的業(yè)務場景中,業(yè)務的執(zhí)行時間可能遠比這里時間長。

我主動讓線程睡上10秒,讓我們再來看看輸出結(jié)果是如何的吧

     @Scheduled(cron = "0/5 * * * * ? ")
     public void testSchedule() {
         try {
             Thread.sleep(10000);
             log.info("當前執(zhí)行任務的線程號ID===>{}", Thread.currentThread().getId());
         } catch (Exception e) {
             e.printStackTrace();
         } 
     }

輸出結(jié)果

 2022-09-06 19:46:50.019  INFO 27236 --- [   scheduling-1] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>64
 2022-09-06 19:47:05.024  INFO 27236 --- [   scheduling-1] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>64
 2022-09-06 19:47:20.016  INFO 27236 --- [   scheduling-1] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>64
 2022-09-06 19:47:35.005  INFO 27236 --- [   scheduling-1] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>64
 2022-09-06 19:47:50.006  INFO 27236 --- [   scheduling-1] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>64

請注意兩個問題:

  • 執(zhí)行時間延遲:從時間上可以明顯看出,不再是每五秒執(zhí)行一次,執(zhí)行時間延遲很多,造成任務的
  • 單線程執(zhí)行:從始至終都只有一個線程在執(zhí)行任務,造成任務的堵塞.

三、為什么會出現(xiàn)上述問題?

問題的根本:線程阻塞式執(zhí)行,執(zhí)行任務線程數(shù)量過少。

那到底是為什么呢?

回到啟動類上,我們在啟動上標明了一個@EnableScheduling注解。

大家在看到諸如@Enablexxxx這樣的注解的時候,就要知道它一定有一個xxxxxAutoConfiguration的自動裝配的類。

@EnableScheduling也不例外,它的自動裝配的類是TaskSchedulingAutoConfiguration。

我們來看看它到底做了一些什么設置?我們?nèi)绾涡薷模?/p>

 @ConditionalOnClass(ThreadPoolTaskScheduler.class)
 @Configuration(proxyBeanMethods = false)
 @EnableConfigurationProperties(TaskSchedulingProperties.class)
 @AutoConfigureAfter(TaskExecutionAutoConfiguration.class)
 public class TaskSchedulingAutoConfiguration {
     @Bean
     @ConditionalOnBean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
     @ConditionalOnMissingBean({ SchedulingConfigurer.class, TaskScheduler.class, ScheduledExecutorService.class })
     public ThreadPoolTaskScheduler taskScheduler(TaskSchedulerBuilder builder) {
         return builder.build();
     }
    // ......
 }

可以看到它也是構(gòu)造了一個 線程池注入到Spring 中

build()調(diào)用繼續(xù)看下去,

 public ThreadPoolTaskScheduler build() {
     return configure(new ThreadPoolTaskScheduler());
 }

ThreadPoolTaskScheduler中,給定的線程池的核心參數(shù)就為1,這也表明了之前為什么只有一條線程在執(zhí)行任務。private volatile int poolSize = 1;

這一段是分開的用代碼不好展示,我用圖片標明出來。

主要邏輯在這里,創(chuàng)建線程池的時候,只使用了三個參數(shù),剩下的都是使用ScheduledExecutorService的默認的參數(shù)

     protected ScheduledExecutorService createExecutor(
             int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) 

而這默認參數(shù)是不行的,生產(chǎn)環(huán)境的大坑,阿里的 Java 開發(fā)手冊中也明確規(guī)定,要手動創(chuàng)建線程池,并給定合適的參數(shù)值~是為什么呢?

因為默認的線程池中, 池中允許的最大線程數(shù)和最大任務等待隊列都是Integer.MAX_VALUE.

大家都懂的,如果使用這玩意,只要出了問題,必定掛~

configure(new ThreadPoolTaskScheduler())這里就是構(gòu)造,略過~

如果已經(jīng)較為熟悉SpringBoot的朋友,現(xiàn)在已然明白解決當前問題的方式~

四、解決方式

1、@EnableConfigurationProperties(TaskSchedulingProperties.class) ,自動裝配類通常也都會對應有個xxxxProperties文件滴,TaskSchedulingProperties也確實可以配置核心線程數(shù)等基本參數(shù),但是無法配置線程池中最大的線程數(shù)量和等待隊列數(shù)量,這種方式還是不合適的。

2、可以手動異步編排,交給某個線程池來執(zhí)行。

3、將定時任務加上異步注解@Async,將其改為異步的定時任務,另外自定義一個系統(tǒng)通用的線程池,讓異步任務使用該線程執(zhí)行任務~

我們分別針對上述三種方式來實現(xiàn)一遍

4.1、修改配置文件

可以配置的就下面幾項~

 spring:
   task:
     scheduling:
       thread-name-prefix: nzc-schedule- #線程名前綴
       pool:
         size: 10 #核心線程數(shù)
      # shutdown:
      #  await-termination: true #執(zhí)行程序是否應等待計劃任務在關(guān)機時完成。
      #   await-termination-period:  #執(zhí)行程序應等待剩余任務完成的最長時間。

測試結(jié)果:

 2022-09-06 20:49:15.015  INFO 7852 --- [ nzc-schedule-1] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>64
 2022-09-06 20:49:30.004  INFO 7852 --- [ nzc-schedule-2] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>66
 2022-09-06 20:49:45.024  INFO 7852 --- [ nzc-schedule-1] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>64
 2022-09-06 20:50:00.025  INFO 7852 --- [ nzc-schedule-3] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>67
 2022-09-06 20:50:15.023  INFO 7852 --- [ nzc-schedule-2] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>66
 2022-09-06 20:50:30.008  INFO 7852 --- [ nzc-schedule-4] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>68

請注意:這里的配置并非是一定生效的,修改后有可能成功,有可能失敗,具體原因未知,但這一點是真實存在的。

不過從執(zhí)行結(jié)果中可以看出,這里的執(zhí)行的線程不再是孤單單的一個。

4.2、執(zhí)行邏輯改為異步執(zhí)行

首先我們先向Spring中注入一個我們自己編寫的線程池,參數(shù)自己設置即可,我這里比較隨意。

 @Configuration
 public class MyTheadPoolConfig {
     @Bean
     public TaskExecutor taskExecutor() {
         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
         //設置核心線程數(shù)
         executor.setCorePoolSize(10);
         //設置最大線程數(shù)
         executor.setMaxPoolSize(20);
         //緩沖隊列200:用來緩沖執(zhí)行任務的隊列
         executor.setQueueCapacity(200);
         //線程活路時間 60 秒
         executor.setKeepAliveSeconds(60);
         //線程池名的前綴:設置好了之后可以方便我們定位處理任務所在的線程池
         // 這里我繼續(xù)沿用 scheduling 默認的線程名前綴
         executor.setThreadNamePrefix("nzc-create-scheduling-");
         //設置拒絕策略
         executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
         executor.setWaitForTasksToCompleteOnShutdown(true);
         return executor;
     }
 }

然后在定時任務這里注入進去:

 /**
  * @description:
  * @author: Ning Zaichun
  * @date: 2022年09月06日 0:02
  */
 @Slf4j
 @Component
 @EnableScheduling
 public class ScheduleService {
     @Autowired
     TaskExecutor taskExecutor;
     @Scheduled(cron = "0/5 * * * * ? ")
     public void testSchedule() {
         CompletableFuture.runAsync(()->{
             try {
                 Thread.sleep(10000);
                 log.info("當前執(zhí)行任務的線程號ID===>{}", Thread.currentThread().getId());
             } catch (Exception e) {
                 e.printStackTrace();
             } 
         },taskExecutor);
     }
 }

測試結(jié)果:

 2022-09-06 21:00:00.019  INFO 18356 --- [te-scheduling-1] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>66
 2022-09-06 21:00:05.022  INFO 18356 --- [te-scheduling-2] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>67
 2022-09-06 21:00:10.013  INFO 18356 --- [te-scheduling-3] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>68
 2022-09-06 21:00:15.020  INFO 18356 --- [te-scheduling-4] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>69
 2022-09-06 21:00:20.026  INFO 18356 --- [te-scheduling-5] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>70

可以看到雖然業(yè)務執(zhí)行時間比較長,但是木有再出現(xiàn),延遲執(zhí)行定時任務的情況。

4.3、異步定時任務

異步定時任務其實和上面的方式原理是一樣的,不過實現(xiàn)稍稍不同罷了。

在定時任務的類上再加一個@EnableAsync注解,給方法添加一個@Async即可。

不過一般@Async都會指定線程池,比如寫成這樣@Async(value = "taskExecutor"),

 /**
  * @description:
  * @author: Ning Zaichun
  * @date: 2022年09月06日 0:02
  */
 @Slf4j
 @Component
 @EnableAsync
 @EnableScheduling
 public class ScheduleService {
     @Autowired
     TaskExecutor taskExecutor;
     @Async(value = "taskExecutor")
     @Scheduled(cron = "0/5 * * * * ? ")
     public void testSchedule() {
             try {
                 Thread.sleep(10000);
                 log.info("當前執(zhí)行任務的線程號ID===>{}", Thread.currentThread().getId());
             } catch (Exception e) {
                 e.printStackTrace();
             } 
     }
 }

執(zhí)行結(jié)果:

 2022-09-06 21:10:15.022  INFO 22760 --- [zc-scheduling-1] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>66
 2022-09-06 21:10:20.021  INFO 22760 --- [zc-scheduling-2] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>67
 2022-09-06 21:10:25.007  INFO 22760 --- [zc-scheduling-3] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>68
 2022-09-06 21:10:30.020  INFO 22760 --- [zc-scheduling-4] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>69
 2022-09-06 21:10:35.007  INFO 22760 --- [zc-scheduling-5] com.nzc.service.ScheduleService          : 當前執(zhí)行任務的線程號ID===>70

結(jié)果顯而易見是可行的啦~

分析

@EnableAsync注解相應的也有一個自動裝配類為TaskExecutionAutoConfiguration

也有一個TaskExecutionProperties配置類,可以在yml文件中對參數(shù)進行設置,這里的話是可以配置線程池最大存活數(shù)量的。

它的默認核心線程數(shù)為8,這里我不再進行演示了,同時它的線程池中最大存活數(shù)量以及任務等待數(shù)量也都為Integer.MAX_VALUE,這也是不建議大家使用默認線程池的原因。

4.4、小結(jié)

 /**
  * 定時任務
  *      1、@EnableScheduling 開啟定時任務
  *      2、@Scheduled開啟一個定時任務
  *      3、自動裝配類 TaskSchedulingAutoConfiguration
  *
  * 異步任務
  *      1、@EnableAsync:開啟異步任務
  *      2、@Async:給希望異步執(zhí)行的方法標注
  *      3、自動裝配類 TaskExecutionAutoConfiguration
  */

實現(xiàn)方式雖不同,但從效率而言,并無太大區(qū)別,覺得那種合適使用那種便可。

不過總結(jié)起來,考查的都是對線程池的理解,對于線程池的了解是真的非常重要的,也很有用處。

五、分布式下的思考

針對上述情況而言,這些解決方法在不引入第三包的情況下是足以應付大部分情況了。

定時框架的實現(xiàn)有許多方式,在此并非打算討論這個。

在單體項目中,也許上面的問題是解決了,但是站在分布式的情況下考慮,就并非是安全的了。

當多個項目在同時運行,那么必然會有多個項目同時這段代碼。

思考:并發(fā)執(zhí)行

如果一個定時任務同時在多個機器中運行,會產(chǎn)生怎么樣的問題?

假如這個定時任務是收集某個信息,發(fā)送給消息隊列,如果多臺機器同時執(zhí)行,同時給消息隊列發(fā)送信息,那么必然導致之后產(chǎn)生一系列的臟數(shù)據(jù)。這是非常不可靠的

解決方式:分布式鎖

很簡單也不簡單,加分布式鎖~ 或者是用一些分布式調(diào)度的框架

如使用XXL-JOB實現(xiàn),或者是其他的定時任務框架。

大家在執(zhí)行這個定時任務之前,先去獲取一把分布式鎖,獲取到了就執(zhí)行,獲取不到就直接結(jié)束。

我這里使用的是 redission,因為方便,打算寫分布式鎖的文章,還在準備當中。

redission官方文檔,我覺得應當算是比較友好的文檔了哈哈

加入依賴:

 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-redis</artifactId>
 </dependency>
 <dependency>
     <groupId>org.redisson</groupId>
     <artifactId>redisson-spring-boot-starter</artifactId>
     <version>3.17.6</version>
 </dependency>

按照文檔說的,編寫配置類,注入 RedissonClient,redisson的全部操作都是基于此。

 /**
  * @description:
  * @author: Ning Zaichun
  * @date: 2022年09月06日 9:31
  */
 @Configuration
 public class MyRedissonConfig {
     /**
      * 所有對Redisson的使用都是通過RedissonClient
      * @return
      * @throws IOException
      */
     @Bean(destroyMethod="shutdown")
     public RedissonClient redissonClient() throws IOException {
         //1、創(chuàng)建配置
         Config config = new Config();
        // 這里規(guī)定要用 redis://+IP地址
           config.useSingleServer().setAddress("redis://xxxxx:6379").setPassword("000415");   // 有密碼就寫密碼~ 木有不用寫~
         //2、根據(jù)Config創(chuàng)建出RedissonClient實例
         //Redis url should start with redis:// or rediss://
         RedissonClient redissonClient = Redisson.create(config);
         return redissonClient;
     }
 }

修改定時任務:

 
 /**
  * @description:
  * @author: Ning Zaichun
  * @date: 2022年09月06日 0:02
  */
 @Slf4j
 @Component
 @EnableAsync
 @EnableScheduling
 public class ScheduleService {
     @Autowired
     TaskExecutor taskExecutor;
     @Autowired
     RedissonClient redissonClient;
     private final String SCHEDULE_LOCK = "schedule:lock";
     @Async(value = "taskExecutor")
     @Scheduled(cron = "0/5 * * * * ? ")
     public void testSchedule() {
         //分布式鎖
         RLock lock = redissonClient.getLock(SCHEDULE_LOCK);
         try {
             //加鎖 10 為時間,加上時間 默認會去掉 redisson 的看門狗機制(即自動續(xù)鎖機制)
             lock.lock(10, TimeUnit.SECONDS);
             Thread.sleep(10000);
             log.info("當前執(zhí)行任務的線程號ID===>{}", Thread.currentThread().getId());
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
             // 一定要記得解鎖~
             lock.unlock();
         }
     }
 }

這里只是給出個大概的實現(xiàn),實際上還是可以優(yōu)化的,比如在給定一個flag,在獲取鎖之前判斷。如果有人搶到鎖,就修改這個值,之后的請求,判斷這個flag,如果不是默認的值,則直接結(jié)束任務等等。

思考:繼續(xù)往深處思考,在分布式情況下如果一個定時任務搶到鎖,但是它在執(zhí)行業(yè)務過程中失敗或者是宕機了,這又該如何處理呢?如何補償呢?

個人思考:

失敗還比較好說,我們可以直接try{}catch(){}中進行通知告警,及時檢查出問題。

如果是掛了,我還沒想好怎么做。

后記

但實際上,我所闡述的這種方式,只能說適用于簡單的單體項目,一旦牽扯到動態(tài)定時任務,使用這種方式就不再那么方便了。

大部分都是使用定時任務框架集成了,尤其是分布式調(diào)度遠比單體項目需要考慮多的多。

以上就是Schedule定時任務在分布式產(chǎn)生的問題詳解的詳細內(nèi)容,更多關(guān)于Schedule定時任務分布式的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JAVACORE與HEAPDUMP生成方法

    JAVACORE與HEAPDUMP生成方法

    JavaCore文件主要保存的是Java應用各線程在某一時刻的運行的位置,即JVM執(zhí)行到哪一個類、哪一個方法、哪一個行上,它是一個文本文件,打開后可以看到每一個線程的執(zhí)行棧,以stack?trace的顯示,本文介紹JAVACORE與HEAPDUMP生成大法,感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • Mybatis動態(tài)SQL?foreach批量操作方法

    Mybatis動態(tài)SQL?foreach批量操作方法

    這篇文章主要介紹了Mybatis動態(tài)SQL?foreach批量操作方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-03-03
  • Rabbitmq延遲隊列實現(xiàn)定時任務的方法

    Rabbitmq延遲隊列實現(xiàn)定時任務的方法

    這篇文章主要介紹了Rabbitmq延遲隊列實現(xiàn)定時任務,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • Java實現(xiàn)bmp和jpeg圖片格式互轉(zhuǎn)

    Java實現(xiàn)bmp和jpeg圖片格式互轉(zhuǎn)

    本文主要介紹了Java實現(xiàn)bmp和jpeg圖片格式互轉(zhuǎn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-04-04
  • 圖解Java經(jīng)典算法快速排序的原理與實現(xiàn)

    圖解Java經(jīng)典算法快速排序的原理與實現(xiàn)

    快速排序是基于二分的思想,對冒泡排序的一種改進。主要思想是確立一個基數(shù),將小于基數(shù)的數(shù)放到基數(shù)左邊,大于基數(shù)的數(shù)字放到基數(shù)的右邊,然后在對這兩部分進一步排序,從而實現(xiàn)對數(shù)組的排序
    2022-09-09
  • Java的內(nèi)存區(qū)域與內(nèi)存溢出異常你了解嗎

    Java的內(nèi)存區(qū)域與內(nèi)存溢出異常你了解嗎

    這篇文章主要為大家詳細介紹了Java的內(nèi)存區(qū)域與內(nèi)存溢出異常,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • 簡單了解JAVA SimpleDateFormat yyyy和YYYY的區(qū)別

    簡單了解JAVA SimpleDateFormat yyyy和YYYY的區(qū)別

    這篇文章主要介紹了簡單了解JAVA SimpleDateFormat yyyy和YYYY的區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-03-03
  • Java中遍歷集合的并發(fā)修改異常解決方案實例代碼

    Java中遍歷集合的并發(fā)修改異常解決方案實例代碼

    當你遍歷集合的同時,又往集合中添加或者刪除元素,就可能報并發(fā)修改異常,下面這篇文章主要給大家介紹了關(guān)于Java中遍歷集合的并發(fā)修改異常解決方案的相關(guān)資料,需要的朋友可以參考下
    2022-12-12
  • Java泛型與數(shù)據(jù)庫應用實例詳解

    Java泛型與數(shù)據(jù)庫應用實例詳解

    這篇文章主要介紹了Java泛型與數(shù)據(jù)庫應用,結(jié)合實例形式詳細分析了java繼承泛型類實現(xiàn)增刪改查操作相關(guān)實現(xiàn)技巧,需要的朋友可以參考下
    2019-08-08
  • 使用Java將字符串在ISO-8859-1和UTF-8之間相互轉(zhuǎn)換

    使用Java將字符串在ISO-8859-1和UTF-8之間相互轉(zhuǎn)換

    大家都知道在一些情況下,我們需要特殊的編碼格式,如:UTF-8,但是系統(tǒng)默認的編碼為ISO-8859-1,遇到這個問題,該如何對字符串進行兩個編碼的轉(zhuǎn)換呢,下面小編給大家分享下java中如何在ISO-8859-1和UTF-8之間相互轉(zhuǎn)換,感興趣的朋友一起看看吧
    2021-12-12

最新評論