欧美阿v视频在线大全_亚洲欧美中文日韩V在线观看_www性欧美日韩欧美91_亚洲欧美日韩久久精品

主頁 > 知識庫 > 利用redis實現分布式鎖,快速解決高并發(fā)時的線程安全問題

利用redis實現分布式鎖,快速解決高并發(fā)時的線程安全問題

熱門標簽:北京400電話辦理收費標準 鄭州人工智能電銷機器人系統(tǒng) 十堰營銷電銷機器人哪家便宜 山東外呼銷售系統(tǒng)招商 宿遷便宜外呼系統(tǒng)平臺 日本中國地圖標注 魔獸2青云地圖標注 貴州電銷卡外呼系統(tǒng) 超呼電話機器人

實際工作中,經常會遇到多線程并發(fā)時的類似搶購的功能,本篇描述一個簡單的redis分布式鎖實現的多線程搶票功能。

直接上代碼。首先按照慣例,給出一個錯誤的示范:

我們可以看看,當20個線程一起來搶10張票的時候,會發(fā)生什么事。

package com.tiger.utils; 
public class TestMutilThread {
 
	// 總票量
	public static int count = 10; 
	public static void main(String[] args) {
		statrtMulti();
	}
 
	public static void statrtMulti() {
		for (int i = 1; i = 20; i++) {
			TicketRunnable tickrunner = new TicketRunnable();
			Thread thread = new Thread(tickrunner, "Thread No: " + i);
			thread.start();
		} 
	}
 
	public static class TicketRunnable implements Runnable {
 
		@Override
		public void run() {
			System.out.println(Thread.currentThread().getName() + " start "
					+ count);
			// TODO Auto-generated method stub
			// logger.info(Thread.currentThread().getName()
			// + " really start" + count);
			if (count = 0) {
				System.out.println(Thread.currentThread().getName()
						+ " ticket sold out ! No tickets remained!" + count);
				return;
			} else {
				count = count - 1;
				System.out.println(Thread.currentThread().getName()
						+ " bought a ticket,now remaining :" + (count));
			}
		}
	}
}

測試結果,從結果可以看到,票數在不同的線程中已經出現混亂。

Thread No: 2 start 10
Thread No: 6 start 10
Thread No: 4 start 10
Thread No: 5 start 10
Thread No: 3 start 10
Thread No: 9 start 6
Thread No: 1 start 10
Thread No: 1 bought a ticket,now remaining :3
Thread No: 9 bought a ticket,now remaining :4
Thread No: 3 bought a ticket,now remaining :5
Thread No: 12 start 3
Thread No: 5 bought a ticket,now remaining :6
Thread No: 4 bought a ticket,now remaining :7
Thread No: 8 start 7
Thread No: 7 start 8
Thread No: 12 bought a ticket,now remaining :1
Thread No: 14 start 0
Thread No: 6 bought a ticket,now remaining :8
Thread No: 16 start 0
Thread No: 2 bought a ticket,now remaining :9
Thread No: 16 ticket sold out ! No tickets remained!0
Thread No: 14 ticket sold out ! No tickets remained!0
Thread No: 18 start 0
Thread No: 18 ticket sold out ! No tickets remained!0
Thread No: 7 bought a ticket,now remaining :0
Thread No: 15 start 0
Thread No: 8 bought a ticket,now remaining :1
Thread No: 13 start 2
Thread No: 19 start 0
Thread No: 11 start 3
Thread No: 11 ticket sold out ! No tickets remained!0
Thread No: 10 start 3
Thread No: 10 ticket sold out ! No tickets remained!0
Thread No: 19 ticket sold out ! No tickets remained!0
Thread No: 13 ticket sold out ! No tickets remained!0
Thread No: 20 start 0
Thread No: 20 ticket sold out ! No tickets remained!0
Thread No: 15 ticket sold out ! No tickets remained!0
Thread No: 17 start 0
Thread No: 17 ticket sold out ! No tickets remained!0

為了解決多線程時出現的混亂問題,這里給出真正的測試類!!!

真正的測試類,這里啟動20個線程,來搶10張票。

RedisTemplate 是用來實現redis操作的,由spring進行集成。這里是使用到了RedisTemplate,所以我以構造器的形式在外部將RedisTemplate傳入到測試類中。

MultiTestLock 是用來實現加鎖的工具類。

總票數使用volatile關鍵字,實現多線程時變量在系統(tǒng)內存中的可見性,這點可以去了解下volatile關鍵字的作用。

TicketRunnable用于模擬搶票功能。

其中由于lock與unlock之間存在if判斷,為保證線程安全,這里使用synchronized來保證。

測試類:

package com.tiger.utils; 
import java.io.Serializable; 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate; 
public class MultiConsumer {
	Logger logger=LoggerFactory.getLogger(MultiTestLock.class);	
	private RedisTemplateSerializable, Serializable> redisTemplate;	
	public MultiTestLock lock;
	//總票量
	public volatile static int count = 10;
 
	public void statrtMulti() {
		lock = new MultiTestLock(redisTemplate);
		for (int i = 1; i = 20; i++) {
			TicketRunnable tickrunner = new TicketRunnable();
			Thread thread = new Thread(tickrunner, "Thread No: " + i);
			thread.start();
			} 
	}
 
	public class TicketRunnable implements Runnable {
 
		@Override
		public void run() {
			logger.info(Thread.currentThread().getName() + " start "
					+ count);
			// TODO Auto-generated method stub
			if (count > 0) {
//				logger.info(Thread.currentThread().getName()
//						+ " really start" + count);
				lock.lock();
				synchronized (this) {
					if(count=0){
						logger.info(Thread.currentThread().getName()
								+ " ticket sold out ! No tickets remained!" + count);
						lock.unlock();
						return;
					}else{
						count=count-1;
						logger.info(Thread.currentThread().getName()
								+ " bought a ticket,now remaining :" + (count));
					}
				}
				lock.unlock();
			}else{
				logger.info(Thread.currentThread().getName()
						+ " ticket sold out !" + count);
			}
		}
	}
 
	public RedisTemplateSerializable, Serializable> getRedisTemplate() {
		return redisTemplate;
	}
 
	public void setRedisTemplate(
			RedisTemplateSerializable, Serializable> redisTemplate) {
		this.redisTemplate = redisTemplate;
	}
 
	public MultiConsumer(RedisTemplateSerializable, Serializable> redisTemplate) {
		super();
		this.redisTemplate = redisTemplate;
	}
}

Lock工具類:

我們知道為保證線程安全,程序中執(zhí)行的操作必須時原子的。redis后續(xù)的版本中可以使用set key同時設置expire超時時間。

想起上次去 電信翼支付 面試時,面試官問過一個問題:分布式鎖如何防止死鎖,問題關鍵在于我們在分布式中進行加鎖操作時成功了,但是后續(xù)業(yè)務操作完畢執(zhí)行解鎖時出現失敗。導致分布式鎖無法釋放。出現死鎖,后續(xù)的加鎖無法正常進行。所以這里設置expire超時時間的目的就是防止出現解鎖失敗的情況,這樣,即使解鎖失敗了,分布式鎖依然會在超時時間過了之后自動釋放。

具體在代碼中也有注釋,也可以作為參考。

package com.tiger.utils; 
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock; 
import javax.sound.midi.MidiDevice.Info; 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.core.script.RedisScript; 
 
public class MultiTestLock implements Lock {	
	Logger logger=LoggerFactory.getLogger(MultiTestLock.class);	
	private RedisTemplateSerializable, Serializable> redisTemplate;	
	public MultiTestLock(RedisTemplateSerializable, Serializable> redisTemplate) {
		super();
		this.redisTemplate = redisTemplate;
	}
 
	@Override
	public void lock() {
		//這里使用while循環(huán)強制線程進來之后先進行搶鎖操作。只有搶到鎖才能進行后續(xù)操作
		while(true){
			if(tryLock()){
				try {
					//這里讓線程睡500毫秒的目的是為了模擬業(yè)務耗時,確保業(yè)務結束時之前設置的值正好打到超時時間,
					//實際生產中可能有偏差,這里需要經驗
					Thread.sleep(500l);
//					logger.info(Thread.currentThread().getName()+" time to awake");
					return;
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}else{
				try {
					//這里設置一個隨機毫秒的sleep目的時降低while循環(huán)的頻率 
					Thread.sleep(new Random().nextInt(200)+100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
 
	@Override
	public boolean tryLock() {
		//這里也可以選用transactionSupport支持事務操作
		SessionCallbackObject> sessionCallback=new SessionCallbackObject>() {
			@Override
			public Object execute(RedisOperations operations)
					throws DataAccessException {
				operations.multi();
				operations.opsForValue().setIfAbsent("secret", "answer");
				//設置超時時間要根據業(yè)務實際的可能處理時間來,是一個經驗值
				operations.expire("secret", 500l, TimeUnit.MILLISECONDS);
				Object object=operations.exec();
				return object;
			}
		};
		//執(zhí)行兩部操作,這里會拿到一個數組值 [true,true],分別對應上述兩部操作的結果,如果中途出現第一次為false則表明第一步set值出錯
		ListBoolean> result=(List) redisTemplate.execute(sessionCallback);
//		logger.info(Thread.currentThread().getName()+" try lock "+ result);
		if(true==result.get(0)||"true".equals(result.get(0)+"")){
			logger.info(Thread.currentThread().getName()+" try lock success");
			return true;
		}else{
			return false;
		}
	}
 
	@Override
	public boolean tryLock(long arg0, TimeUnit arg1)
			throws InterruptedException {
		// TODO Auto-generated method stub
		return false;
	}
 
	@Override
	public void unlock() {
		//unlock操作直接刪除鎖,如果執(zhí)行完還沒有達到超時時間則直接刪除,讓后續(xù)的線程進行繼續(xù)操作。起到補刀的作用,確保鎖已經超時或被刪除
		SessionCallbackObject> sessionCallback=new SessionCallbackObject>() {
			@Override
			public Object execute(RedisOperations operations)
					throws DataAccessException {
				operations.multi();
				operations.delete("secret");
				Object object=operations.exec();
				return object;
			}
		};
		Object result=redisTemplate.execute(sessionCallback);
	} 
 
	@Override
	public void lockInterruptibly() throws InterruptedException {
		// TODO Auto-generated method stub
	}
 
	@Override
	public Condition newCondition() {
		// TODO Auto-generated method stub
		return null;
	}
	
	public RedisTemplateSerializable, Serializable> getRedisTemplate() {
		return redisTemplate;
	}
 
	public void setRedisTemplate(
			RedisTemplateSerializable, Serializable> redisTemplate) {
		this.redisTemplate = redisTemplate;
	}
}

執(zhí)行結果

可以看到,票數穩(wěn)步減少,后續(xù)沒有搶到鎖的線程余票為0,無票可搶。

tips:

這其中也出現了一個問題,redis進行多部封裝操作時,系統(tǒng)報錯:ERR EXEC without MULTI

后經過查閱發(fā)現問題出在:

在spring中,多次執(zhí)行MULTI命令不會報錯,因為第一次執(zhí)行時,會將其內部的一個isInMulti變量設為true,后續(xù)每次執(zhí)行命令是都會檢查這個變量,如果為true,則不執(zhí)行命令。

而多次執(zhí)行EXEC命令則會報開頭說的"ERR EXEC without MULTI"錯誤。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。如有錯誤或未考慮完全的地方,望不吝賜教。

您可能感興趣的文章:
  • 詳解redis分布式鎖的這些坑
  • 基于Redis實現分布式鎖的方法(lua腳本版)
  • SpringBoot之使用Redis實現分布式鎖(秒殺系統(tǒng))
  • 詳解Redis 分布式鎖遇到的序列化問題
  • 詳解RedisTemplate下Redis分布式鎖引發(fā)的系列問題
  • redisson分布式鎖的用法大全
  • php基于redis的分布式鎖實例詳解
  • Redis分布式鎖升級版RedLock及SpringBoot實現方法
  • 詳解基于redis實現分布式鎖

標簽:北京 吉安 大慶 楊凌 江蘇 朝陽 臺州 果洛

巨人網絡通訊聲明:本文標題《利用redis實現分布式鎖,快速解決高并發(fā)時的線程安全問題》,本文關鍵詞  利用,redis,實現,分布式,;如發(fā)現本文內容存在版權問題,煩請?zhí)峁┫嚓P信息告之我們,我們將及時溝通與處理。本站內容系統(tǒng)采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《利用redis實現分布式鎖,快速解決高并發(fā)時的線程安全問題》相關的同類信息!
  • 本頁收集關于利用redis實現分布式鎖,快速解決高并發(fā)時的線程安全問題的相關信息資訊供網民參考!
  • 推薦文章
    欧美阿v视频在线大全_亚洲欧美中文日韩V在线观看_www性欧美日韩欧美91_亚洲欧美日韩久久精品
  • <rt id="w000q"><acronym id="w000q"></acronym></rt>
  • <abbr id="w000q"></abbr>
    <rt id="w000q"></rt>
    国产精品久久久久9999吃药| 黄色日韩网站视频| 欧美体内she精高潮| 黄色录像免费观看| 国产亚洲欧美在线| 国产一区二区三区观看| 性猛交娇小69hd| 26uuu亚洲婷婷狠狠天堂| 秋霞国产午夜精品免费视频| 菠萝菠萝蜜网站| 91精品国产aⅴ一区二区| 亚洲成人av一区二区三区| 性活交片大全免费看| 欧美日韩一级大片网址| 亚洲国产精品久久不卡毛片| 国产日韩视频一区| 日韩欧美成人一区二区| 免费精品99久久国产综合精品| 欧美熟妇精品黑人巨大一二三区| 欧美一区二区大片| 免费黄网站欧美| 日韩不卡av在线| 久久久亚洲精品一区二区三区| 韩国成人福利片在线播放| 日韩视频在线观看免费视频| 国产片一区二区| 成人一区二区视频| 在线视频国内自拍亚洲视频| 亚洲午夜羞羞片| 内射中出日韩无国产剧情| 欧美白人最猛性xxxxx69交| 韩国午夜理伦三级不卡影院| 日本视频在线免费| b站大片免费直播| 久久综合九色综合97婷婷| 国产乱码一区二区三区| 国产精品久久久精品四季影院| 亚洲女女做受ⅹxx高潮| 大桥未久恸哭の女教师| 欧美电视剧在线观看完整版| 国产一区999| 一本高清dvd不卡在线观看 | 欧美成人精品1314www| 国内外成人在线| 国产又黄又爽又无遮挡| 亚洲一区二区三区自拍| 在线精品一区二区三区| 国产视频一区二区在线| 永久看看免费大片| 日韩一级片网址| 国产精品系列在线观看| 欧美亚洲国产bt| 免费在线视频一区| 污软件在线观看| 玉米视频成人免费看| 黄色录像a级片| 欧美国产成人在线| 国产成人av片| 久久亚洲一区二区三区明星换脸| 成人动漫视频在线| 91精品福利在线一区二区三区| 国产精品1区2区3区| 欧美日韩中文字幕一区| 激情综合网av| 欧美在线观看18| 国产美女娇喘av呻吟久久| 欧美亚州韩日在线看免费版国语版| 日本视频免费一区| 日韩福利小视频| 日韩在线一二三区| 最新一区二区三区| 欧美aaaaaa午夜精品| 色综合夜色一区| 麻豆精品一二三| 欧美在线一二三| 狠狠色丁香婷婷综合| 欧美人体做爰大胆视频| 国产精品69毛片高清亚洲| 7777精品伊人久久久大香线蕉超级流畅 | 国产在线精品不卡| 欧美人妇做爰xxxⅹ性高电影| 国产成+人+日韩+欧美+亚洲| 日韩三级中文字幕| 久久综合桃花网| 欧美经典一区二区三区| 少妇精品一区二区三区| 一区二区高清免费观看影视大全| 特级西西人体高清大胆| 免费的成人av| 欧美区在线观看| 成人免费毛片app| 久久色中文字幕| 久久福利小视频| 亚洲免费av在线| 亚洲一二三在线观看| 老司机精品视频线观看86| 欧美日韩免费视频| av在线不卡网| 中文一区二区完整视频在线观看| 亚洲综合色一区| 日韩极品在线观看| 欧美色图天堂网| 99热精品一区二区| 中文字幕第一页久久| 中文字幕欧美激情极品| 免费成人在线影院| 欧美一区二区三区在线观看视频| 国产精品欧美性爱| 亚洲日本一区二区| 2021亚洲天堂| 高潮精品一区videoshd| 国产亚洲精品bt天堂精选| 国产aⅴ激情无码久久久无码| 日韩中文欧美在线| 欧美一区日韩一区| 亚洲av成人片色在线观看高潮 | 午夜写真片福利电影网| 国产宾馆实践打屁股91| 久久蜜桃av一区精品变态类天堂| 欧美一区二区三区成人精品| 天天综合色天天综合| 欧美区视频在线观看| 日韩精品xxx| 亚洲一区二区3| 欧美色图免费看| 手机看片国产精品| 亚洲国产综合在线| 精品视频全国免费看| 久久久久中文字幕亚洲精品| 一区二区激情视频| 欧美日韩国产一区| 国产精品熟妇一区二区三区四区| 亚洲高清三级视频| 91麻豆精品国产综合久久久久久| 日韩www视频| 美女精品一区二区| 久久综合色鬼综合色| 国产aaaaaaaaa| 国产成+人+日韩+欧美+亚洲| 亚洲欧洲一区二区在线播放| 在线观看一区不卡| 99久久久无码国产精品性波多| 亚洲1区2区3区视频| 欧美一区二区在线免费观看| 久久精品成人av| 国产精品一区二区在线观看网站| 国产精品少妇自拍| 欧美在线免费观看亚洲| 人妻激情偷乱频一区二区三区| 首页国产欧美日韩丝袜| 日韩精品在线一区二区| 懂色av粉嫩av浪潮av| 成人午夜激情影院| 一区二区国产视频| 日韩限制级电影在线观看| 亚洲第一综合网| 粉嫩av一区二区三区在线播放 | 亚洲欧洲一区二区三区| 欧美三级日本三级少妇99| 丝袜熟女一区二区三区| 久久精品久久综合| 国产精品素人一区二区| 在线一区二区三区四区| 中文字幕乱码在线| 国内国产精品久久| 亚洲欧美另类久久久精品2019| 欧美精品一二三四| 欧美激情视频二区| 99久久综合色| 日韩电影在线一区| 国产欧美日韩中文久久| 欧美午夜一区二区三区| wwwwww日本| 不卡高清视频专区| 日韩综合小视频| 国产免费观看久久| 欧美日韩国产系列| 天天操天天舔天天射| 91丨九色丨国产丨porny| 日本一区中文字幕| 日韩一区在线播放| 欧美一区二区不卡视频| 亚洲一级二级片| 色哟哟视频在线| 国产麻豆精品视频| 亚洲国产精品一区二区久久 | 韩国毛片一区二区三区| 亚洲精品视频自拍| 欧美精品一区二区精品网| 欧美在线综合视频| 国产黄色录像视频| 精品人妻一区二区免费| 国产成人精品免费网站| 图片区小说区国产精品视频| 国产精品久久久久久一区二区三区| 91精品国产91久久久久久最新毛片 | 日韩美女精品在线| 精品国产一区二区亚洲人成毛片| 在线免费观看日韩欧美| 91麻豆精品国产91久久综合|