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

SpringCloud?分布式鎖的多種實現(xiàn)

 更新時間:2022年04月11日 15:41:49   作者:Resourceful!  
本文主要介紹了SpringCloud?分布式鎖的多種實現(xiàn),主要有三種方式,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下

前言

今天跟大家探討一下分布式鎖的設(shè)計與實現(xiàn)。

  • 分布式鎖概述
  • 數(shù)據(jù)庫分布式鎖
  • Redis分布式鎖
  • Zookeeper分布式鎖
  • 三種分布式鎖對比

1. 分布式鎖概述

我們的系統(tǒng)都是分布式部署的,日常開發(fā)中,秒殺下單、搶購商品等等業(yè)務(wù)場景,為了防?庫存超賣,都需要用到分布式鎖。

分布式鎖其實就是,控制分布式系統(tǒng)不同進(jìn)程共同訪問共享資源的一種鎖的實現(xiàn)。如果不同的系統(tǒng)或同一個系統(tǒng)的不同主機(jī)之間共享了某個臨界資源,往往需要互斥來防止彼此干擾,以保證一致性。

業(yè)界流行的分布式鎖實現(xiàn),一般有這3種方式:

  • 基于數(shù)據(jù)庫實現(xiàn)的分布式鎖
  • 基于Redis實現(xiàn)的分布式鎖
  • 基于Zookeeper實現(xiàn)的分布式鎖

2. 基于數(shù)據(jù)庫的分布式鎖

2.1 數(shù)據(jù)庫悲觀鎖實現(xiàn)的分布式鎖

可以使用select ... for update 來實現(xiàn)分布式鎖。我們自己的項目,分布式定時任務(wù),就使用類似的實現(xiàn)方案,我給大家來展示個簡單版的哈

表結(jié)構(gòu)如下:

CREATE TABLE `t_resource_lock` (
  `key_resource` varchar(45) COLLATE utf8_bin NOT NULL DEFAULT '資源主鍵',
  `status` char(1) COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'S,F,P',
  `lock_flag` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '1是已經(jīng)鎖 0是未鎖',
  `begin_time` datetime DEFAULT NULL COMMENT '開始時間',
  `end_time` datetime DEFAULT NULL COMMENT '結(jié)束時間',
  `client_ip` varchar(45) COLLATE utf8_bin NOT NULL DEFAULT '搶到鎖的IP',
  `time` int(10) unsigned NOT NULL DEFAULT '60' COMMENT '方法生命周期內(nèi)只允許一個結(jié)點獲取一次鎖,單位:分鐘',
  PRIMARY KEY (`key_resource`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin

加鎖lock方法的偽代碼如下:

@Transcational //一定要加事務(wù)
public boolean lock(String keyResource,int time){
   resourceLock = 'select * from t_resource_lock where key_resource ='#{keySource}' for update';
   
   try{
    if(resourceLock==null){
      //插入鎖的數(shù)據(jù)
      resourceLock = new ResourceLock();
      resourceLock.setTime(time);
      resourceLock.setLockFlag(1);  //上鎖
      resourceLock.setStatus(P); //處理中
      resourceLock.setBeginTime(new Date());
      int count = "insert into resourceLock"; 
      if(count==1){
         //獲取鎖成功
         return true;
      }
      return false;
   }
   }catch(Exception x){
      return false;
   }
   
   //沒上鎖并且鎖已經(jīng)超時,即可以獲取鎖成功
   if(resourceLock.getLockFlag=='0'&&'S'.equals(resourceLock.getstatus)
    && new Date()>=resourceLock.addDateTime(resourceLock.getBeginTime(,time)){
      resourceLock.setLockFlag(1);  //上鎖
      resourceLock.setStatus(P); //處理中
      resourceLock.setBeginTime(new Date());
      //update resourceLock;
      return true;
   }else if(new Date()>=resourceLock.addDateTime(resourceLock.getBeginTime(,time)){
     //超時未正常執(zhí)行結(jié)束,獲取鎖失敗
     return false;
   }else{
     return false;
   } 
}

解鎖unlock方法的偽代碼如下:

public void unlock(String v,status){
      resourceLock.setLockFlag(0);  //解鎖
      resourceLock.setStatus(status); S:表示成功,F(xiàn)表示失敗
      //update resourceLock;
      return ;
}

整體流程:

try{
if(lock(keyResource,time)){ //加鎖
   status = process();//你的業(yè)務(wù)邏輯處理。
 }
} finally{
    unlock(keyResource,status); //釋放鎖
}

其實這個悲觀鎖實現(xiàn)的分布式鎖,整體的流程還是比較清晰的。就是先select ... for update 鎖住主鍵key_resource那個記錄,如果為空,則可以插入一條記錄,如果已有記錄判斷下狀態(tài)和時間是否已經(jīng)超時。這里需要注意一下哈,必須要加事務(wù)哈。

2.2 數(shù)據(jù)庫樂觀鎖實現(xiàn)的分布式鎖

除了悲觀鎖,還可以用樂觀鎖實現(xiàn)分布式鎖。樂觀鎖,顧名思義,就是很樂觀,每次更新操作,都覺得不會存在并發(fā)沖突,只有更新失敗后,才重試。它是基于CAS思想實現(xiàn)的。我以前的公司,扣減余額就是用這種方案。

搞個version字段,每次更新修改,都會自增加一,然后去更新余額時,把查出來的那個版本號,帶上條件去更新,如果是上次那個版本號,就更新,如果不是,表示別人并發(fā)修改過了,就繼續(xù)重試。

大概流程如下:

查詢版本號和余額

select version,balance from account where user_id ='666';

假設(shè)查到版本號是oldVersion=1.

邏輯處理,判斷余額

if(balance<扣減金額){
   return;
}

left_balance = balance - 扣減金額;

進(jìn)行扣減余額

update account set balance = #{left_balance} ,version = version+1 where version 
= #{oldVersion} and balance>= #{left_balance} and user_id ='666';

大家可以看下這個流程圖哈:

圖片

這種方式適合并發(fā)不高的場景,一般需要設(shè)置一下重試的次數(shù)

3.基于Redis實現(xiàn)的分布式鎖

Redis分布式鎖一般有以下這幾種實現(xiàn)方式:

  • setnx + expire
  • setnx + value值是過期時間
  • set的擴(kuò)展命令(set ex px nx)
  • set ex px nx + 校驗唯一隨機(jī)值,再刪除
  • Redisson
  • Redisson + RedLock

3.1 setnx + expire

聊到Redis分布式鎖,很多小伙伴反手就是setnx + expire,如下:

if(jedis.setnx(key,lock_value) == 1){ //setnx加鎖
    expire(key,100); //設(shè)置過期時間
    try {
        do something  //業(yè)務(wù)處理
    }catch(){
    }
  finally {
       jedis.del(key); //釋放鎖
    }
}

這段代碼是可以加鎖成功,但是你有沒有發(fā)現(xiàn)問題,加鎖操作和設(shè)置超時時間是分開的。假設(shè)在執(zhí)行完setnx加鎖后,正要執(zhí)行expire設(shè)置過期時間時,進(jìn)程crash掉或者要重啟維護(hù)了,那這個鎖就長生不老了,別的線程永遠(yuǎn)獲取不到鎖啦,所以分布式鎖不能這么實現(xiàn)!

3.2 setnx + value值是過期時間

long expires = System.currentTimeMillis() + expireTime; //系統(tǒng)時間+設(shè)置的過期時間
String expiresStr = String.valueOf(expires);

// 如果當(dāng)前鎖不存在,返回加鎖成功
if (jedis.setnx(key, expiresStr) == 1) {
        return true;
} 
// 如果鎖已經(jīng)存在,獲取鎖的過期時間
String currentValueStr = jedis.get(key);

// 如果獲取到的過期時間,小于系統(tǒng)當(dāng)前時間,表示已經(jīng)過期
if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {

     // 鎖已過期,獲取上一個鎖的過期時間,并設(shè)置現(xiàn)在鎖的過期時間(不了解redis的getSet命令的小伙伴,可以去官網(wǎng)看下哈)
    String oldValueStr = jedis.getSet(key, expiresStr);
    
    if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
         // 考慮多線程并發(fā)的情況,只有一個線程的設(shè)置值和當(dāng)前值相同,它才可以加鎖
         return true;
    }
}
        
//其他情況,均返回加鎖失敗
return false;
}

日常開發(fā)中,有些小伙伴就是這么實現(xiàn)分布式鎖的,但是會有這些缺點

  • 過期時間是客戶端自己生成的,分布式環(huán)境下,每個客戶端的時間必須同步。
  • 沒有保存持有者的唯一標(biāo)識,可能被別的客戶端釋放/解鎖。
  • 鎖過期的時候,并發(fā)多個客戶端同時請求過來,都執(zhí)行了jedis.getSet(),最終只能有一個客戶端加鎖成功,但是該客戶端鎖的過期時間,可能被別的客戶端覆蓋。

3.3 set的擴(kuò)展命令(set ex px nx)

這個命令的幾個參數(shù)分別表示什么意思呢?跟大家復(fù)習(xí)一下:

SET key value [EX seconds] [PX milliseconds] [NX|XX]
  • EX second :設(shè)置鍵的過期時間為second秒。
  • PX millisecond :設(shè)置鍵的過期時間為millisecond毫秒。
  • NX :只在鍵不存在時,才對鍵進(jìn)行設(shè)置操作。
  • XX :只在鍵已經(jīng)存在時,才對鍵進(jìn)行設(shè)置操作。
if(jedis.set(key, lock_value, "NX", "EX", 100s) == 1){ //加鎖
    try {
        do something  //業(yè)務(wù)處理
    }catch(){
  }
  finally {
       jedis.del(key); //釋放鎖
    }
}

這個方案可能存在這樣的問題:

  • 鎖過期釋放了,業(yè)務(wù)還沒執(zhí)行完。
  • 鎖被別的線程誤刪。

有些伙伴可能會有個疑問,就是鎖為什么會被別的線程誤刪呢?假設(shè)并發(fā)多線程場景下,線程A獲得了鎖,但是它沒釋放鎖的話,線程B是獲取不到鎖的,所以按道理它是執(zhí)行不到加鎖下面的代碼滴,怎么會導(dǎo)致鎖被別的線程誤刪呢?

假設(shè)線程A和B,都想用key加鎖,最后A搶到鎖加鎖成功,但是由于執(zhí)行業(yè)務(wù)邏輯的耗時很長,超過了設(shè)置的超時時間100s。這時候,Redis就自動釋放了key鎖。這時候線程B就可以加鎖成功了,接下啦,它也執(zhí)行業(yè)務(wù)邏輯處理。假設(shè)碰巧這時候,A執(zhí)行完自己的業(yè)務(wù)邏輯,它就去釋放鎖,但是它就把B的鎖給釋放了。

3.4 set ex px nx + 校驗唯一隨機(jī)值,再刪除

為了解決鎖被別的線程誤刪問題??梢栽?code>set ex px nx的基礎(chǔ)上,加上個校驗的唯一隨機(jī)值,如下:

if(jedis.set(key, uni_request_id, "NX", "EX", 100s) == 1){ //加鎖
    try {
        do something  //業(yè)務(wù)處理
    }catch(){
  }
  finally {
       //判斷是不是當(dāng)前線程加的鎖,是才釋放
       if (uni_request_id.equals(jedis.get(key))) {
          jedis.del(key); //釋放鎖
        }
    }
}

在這里,判斷當(dāng)前線程加的鎖和釋放鎖不是一個原子操作。如果調(diào)用jedis.del()釋放鎖的時候,可能這把鎖已經(jīng)不屬于當(dāng)前客戶端,會解除他人加的鎖。

一般可以用lua腳本來包一下。lua腳本如下:

if redis.call('get',KEYS[1]) == ARGV[1] then 
   return redis.call('del',KEYS[1]) 
else
   return 0
end;

這種方式比較不錯了,一般情況下,已經(jīng)可以使用這種實現(xiàn)方式。但是還是存在:鎖過期釋放了,業(yè)務(wù)還沒執(zhí)行完的問題

3.5 Redisson

對于可能存在鎖過期釋放,業(yè)務(wù)沒執(zhí)行完的問題。我們可以稍微把鎖過期時間設(shè)置長一些,大于正常業(yè)務(wù)處理時間就好啦。如果你覺得不是很穩(wěn),還可以給獲得鎖的線程,開啟一個定時守護(hù)線程,每隔一段時間檢查鎖是否還存在,存在則對鎖的過期時間延長,防止鎖過期提前釋放。

當(dāng)前開源框架Redisson解決了這個問題??梢钥聪翿edisson底層原理圖:

圖片

只要線程一加鎖成功,就會啟動一個watch dog看門狗,它是一個后臺線程,會每隔10秒檢查一下,如果線程1還持有鎖,那么就會不斷的延長鎖key的生存時間。因此,Redisson就是使用watch dog解決了鎖過期釋放,業(yè)務(wù)沒執(zhí)行完問題

3.6 Redisson + RedLock

前面六種方案都只是基于Redis單機(jī)版的分布式鎖討論,還不是很完美。因為Redis一般都是集群部署的:

圖片

如果線程一在Redismaster節(jié)點上拿到了鎖,但是加鎖的key還沒同步到slave節(jié)點。恰好這時,master節(jié)點發(fā)生故障,一個slave節(jié)點就會升級為master節(jié)點。線程二就可以順理成章獲取同個key的鎖啦,但線程一也已經(jīng)拿到鎖了,鎖的安全性就沒了。

為了解決這個問題,Redis作者antirez提出一種高級的分布式鎖算法:Redlock。它的核心思想是這樣的:

部署多個Redis master,以保證它們不會同時宕掉。并且這些master節(jié)點是完全相互獨立的,相互之間不存在數(shù)據(jù)同步。同時,需要確保在這多個master實例上,是與在Redis單實例,使用相同方法來獲取和釋放鎖。

我們假設(shè)當(dāng)前有5個Redis master節(jié)點,在5臺服務(wù)器上面運行這些Redis實例。

圖片

RedLock的實現(xiàn)步驟:

  • 獲取當(dāng)前時間,以毫秒為單位。
  • 按順序向5個master節(jié)點請求加鎖??蛻舳嗽O(shè)置網(wǎng)絡(luò)連接和響應(yīng)超時時間,并且超時時間要小于鎖的失效時間。(假設(shè)鎖自動失效時間為10秒,則超時時間一般在5-50毫秒之間,我們就假設(shè)超時時間是50ms吧)。如果超時,跳過該master節(jié)點,盡快去嘗試下一個master節(jié)點。
  • 客戶端使用當(dāng)前時間減去開始獲取鎖時間(即步驟1記錄的時間),得到獲取鎖使用的時間。當(dāng)且僅當(dāng)超過一半(N/2+1,這里是5/2+1=3個節(jié)點)的Redis master節(jié)點都獲得鎖,并且使用的時間小于鎖失效時間時,鎖才算獲取成功。(如上圖,10s> 30ms+40ms+50ms+4m0s+50ms)
  • 如果取到了鎖,key的真正有效時間就變啦,需要減去獲取鎖所使用的時間。
  • 如果獲取鎖失?。]有在至少N/2+1個master實例取到鎖,有或者獲取鎖時間已經(jīng)超過了有效時間),客戶端要在所有的master節(jié)點上解鎖(即便有些master節(jié)點根本就沒有加鎖成功,也需要解鎖,以防止有些漏網(wǎng)之魚)。

簡化下步驟就是:

  • 按順序向5個master節(jié)點請求加鎖
  • 根據(jù)設(shè)置的超時時間來判斷,是不是要跳過該master節(jié)點。
  • 如果大于等于3個節(jié)點加鎖成功,并且使用的時間小于鎖的有效期,即可認(rèn)定加鎖成功啦。
  • 如果獲取鎖失敗,解鎖!

Redisson實現(xiàn)了redLock版本的鎖,有興趣的小伙伴,可以去了解一下哈~

4. Zookeeper分布式鎖

在學(xué)習(xí)Zookeeper分布式鎖之前,我們復(fù)習(xí)一下Zookeeper的節(jié)點哈。

Zookeeper的節(jié)點Znode有四種類型:

  • 持久節(jié)點:默認(rèn)的節(jié)點類型。創(chuàng)建節(jié)點的客戶端與zookeeper斷開連接后,該節(jié)點依舊存在。
  • 持久節(jié)點順序節(jié)點:所謂順序節(jié)點,就是在創(chuàng)建節(jié)點時,Zookeeper根據(jù)創(chuàng)建的時間順序給該節(jié)點名稱進(jìn)行編號,持久節(jié)點順序節(jié)點就是有順序的持久節(jié)點。
  • 臨時節(jié)點:和持久節(jié)點相反,當(dāng)創(chuàng)建節(jié)點的客戶端與zookeeper斷開連接后,臨時節(jié)點會被刪除。
  • 臨時順序節(jié)點:有順序的臨時節(jié)點。

Zookeeper分布式鎖實現(xiàn)應(yīng)用了臨時順序節(jié)點。這里不貼代碼啦,來講下zk分布式鎖的實現(xiàn)原理吧。

4.1 zk獲取鎖過程

當(dāng)?shù)谝粋€客戶端請求過來時,Zookeeper客戶端會創(chuàng)建一個持久節(jié)點locks。如果它(Client1)想獲得鎖,需要在locks節(jié)點下創(chuàng)建一個順序節(jié)點lock1.如圖

圖片

接著,客戶端Client1會查找locks下面的所有臨時順序子節(jié)點,判斷自己的節(jié)點lock1是不是排序最小的那一個,如果是,則成功獲得鎖。

圖片

這時候如果又來一個客戶端client2前來嘗試獲得鎖,它會在locks下再創(chuàng)建一個臨時節(jié)點lock2

圖片

客戶端client2一樣也會查找locks下面的所有臨時順序子節(jié)點,判斷自己的節(jié)點lock2是不是最小的,此時,發(fā)現(xiàn)lock1才是最小的,于是獲取鎖失敗。獲取鎖失敗,它是不會甘心的,client2向它排序靠前的節(jié)點lock1注冊Watcher事件,用來監(jiān)聽lock1是否存在,也就是說client2搶鎖失敗進(jìn)入等待狀態(tài)。

圖片

此時,如果再來一個客戶端Client3來嘗試獲取鎖,它會在locks下再創(chuàng)建一個臨時節(jié)點lock3

圖片

同樣的,client3一樣也會查找locks下面的所有臨時順序子節(jié)點,判斷自己的節(jié)點lock3是不是最小的,發(fā)現(xiàn)自己不是最小的,就獲取鎖失敗。它也是不會甘心的,它會向在它前面的節(jié)點lock2注冊Watcher事件,以監(jiān)聽lock2節(jié)點是否存在。

圖片

4.2 釋放鎖

我們再來看看釋放鎖的流程,Zookeeper的客戶端業(yè)務(wù)完成或者發(fā)生故障,都會刪除臨時節(jié)點,釋放鎖。如果是任務(wù)完成,Client1會顯式調(diào)用刪除lock1的指令

圖片

如果是客戶端故障了,根據(jù)臨時節(jié)點得特性,lock1是會自動刪除的

圖片

lock1節(jié)點被刪除后,Client2可開心了,因為它一直監(jiān)聽著lock1。lock1節(jié)點刪除,Client2立刻收到通知,也會查找locks下面的所有臨時順序子節(jié)點,發(fā)下lock2是最小,就獲得鎖。

圖片

同理,Client2獲得鎖之后,Client3也對它虎視眈眈,啊哈哈~

  • Zookeeper設(shè)計定位就是分布式協(xié)調(diào),簡單易用。如果獲取不到鎖,只需添加一個監(jiān)聽器即可,很適合做分布式鎖。
  • Zookeeper作為分布式鎖也缺點:如果有很多的客戶端頻繁的申請加鎖、釋放鎖,對于Zookeeper集群的壓力會比較大。

5. 三種分布式鎖對比

5.1 數(shù)據(jù)庫分布式鎖實現(xiàn)

優(yōu)點:

簡單,使用方便,不需要引入Redis、zookeeper等中間件。

缺點:

  • 不適合高并發(fā)的場景
  • db操作性能較差;

5.2 Redis分布式鎖實現(xiàn)

優(yōu)點:

  • 性能好,適合高并發(fā)場景
  • 較輕量級
  • 有較好的框架支持,如Redisson

缺點:

  • 過期時間不好控制
  • 需要考慮鎖被別的線程誤刪場景

5.3 Zookeeper分布式鎖實現(xiàn)

缺點:

  • 性能不如redis實現(xiàn)的分布式鎖
  • 比較重的分布式鎖。

優(yōu)點:

  • 有較好的性能和可靠性
  • 有封裝較好的框架,如Curator

5.4 對比匯總

  • 從性能角度(從高到低)Redis > Zookeeper >= 數(shù)據(jù)庫;
  • 從理解的難易程度角度(從低到高)數(shù)據(jù)庫 > Redis > Zookeeper;
  • 從實現(xiàn)的復(fù)雜性角度(從低到高)Zookeeper > Redis > 數(shù)據(jù)庫;
  • 從可靠性角度(從高到低)Zookeeper > Redis > 數(shù)據(jù)庫。

到此這篇關(guān)于SpringCloud 分布式鎖的多種實現(xiàn)的文章就介紹到這了,更多相關(guān)SpringCloud 分布式鎖 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring事件Application Event原理詳解

    Spring事件Application Event原理詳解

    這篇文章主要介紹了Spring 事件Application Event原理詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-02-02
  • java文件操作工具類分享(file文件工具類)

    java文件操作工具類分享(file文件工具類)

    java文件操作工具類(文件工具類)
    2014-01-01
  • Java中命令行參數(shù)--與-D的區(qū)別

    Java中命令行參數(shù)--與-D的區(qū)別

    本文主要介紹了Java中命令行參數(shù)--與-D的區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • Netty分布式server啟動流程N(yùn)io創(chuàng)建源碼分析

    Netty分布式server啟動流程N(yùn)io創(chuàng)建源碼分析

    這篇文章主要介紹了Netty分布式server啟動流程N(yùn)io創(chuàng)建源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03
  • 比較排序之快速排序(實例代碼)

    比較排序之快速排序(實例代碼)

    下面小編就為大家?guī)硪黄容^排序之快速排序(實例代碼)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • Java使用Freemarker頁面靜態(tài)化生成的實現(xiàn)

    Java使用Freemarker頁面靜態(tài)化生成的實現(xiàn)

    這篇文章主要介紹了Java使用Freemarker頁面靜態(tài)化生成的實現(xiàn),頁面靜態(tài)化是將原來的動態(tài)網(wǎng)頁改為通過靜態(tài)化技術(shù)生成的靜態(tài)網(wǎng)頁,FreeMarker?是一個用?Java?語言編寫的模板引擎,它基于模板來生成文本輸,更多相關(guān)內(nèi)容需要的小伙伴可以參考一下
    2022-06-06
  • spring boot實現(xiàn)圖片上傳和下載功能

    spring boot實現(xiàn)圖片上傳和下載功能

    這篇文章主要為大家詳細(xì)介紹了spring boot實現(xiàn)圖片上傳和下載功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • 關(guān)于log4j日志擴(kuò)展---自定義PatternLayout

    關(guān)于log4j日志擴(kuò)展---自定義PatternLayout

    這篇文章主要介紹了關(guān)于log4j日志擴(kuò)展---自定義PatternLayout,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • SpringBoot中使用Quartz設(shè)置定時任務(wù)的實例詳解

    SpringBoot中使用Quartz設(shè)置定時任務(wù)的實例詳解

    Quartz是OpenSymphony開源組織在任務(wù)調(diào)度領(lǐng)域的一個開源項目,完全基于 Java 實現(xiàn),本文小編給大家介紹了SpringBoot中如何使用Quartz設(shè)置定時任務(wù),文中通過代碼示例給大家講解的非常詳細(xì),需要的朋友可以參考下
    2023-12-12
  • 深入解析Java的線程同步以及線程間通信

    深入解析Java的線程同步以及線程間通信

    這篇文章主要介紹了Java的線程同步以及線程間通信,多線程編程是Java學(xué)習(xí)中的重點和難點,需要的朋友可以參考下
    2015-09-09

最新評論