java端在使用jedispool 連接redis的時候,在高并發的時候經常死鎖,或報連接異常,JedisConnectionException,或者getResource 異常等各種問題
在使用jedispool 的時候一定要注意兩點
1。 在獲取 jedisPool和jedis的時候加上線程同步,保證不要創建過多的jedispool 和 jedis
2。 用完Jedis實例后需要返還給JedisPool
整理了一下redis工具類,通過大量測試和高并發測試的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
package com.caspar.util; import java.util.concurrent.locks.ReentrantLock; import org.apache.log4j.Logger; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; /** * Redis 工具類 * @author caspar * */ public class RedisUtil { protected static ReentrantLock lockPool = new ReentrantLock(); protected static ReentrantLock lockJedis = new ReentrantLock(); protected static Logger logger = Logger.getLogger(RedisUtil. class ); //Redis服務器IP private static String ADDR_ARRAY = FileUtil.getPropertyValue( "/properties/redis.properties" , "server" ); //Redis的端口號 private static int PORT = FileUtil.getPropertyValueInt( "/properties/redis.properties" , "port" ); //訪問密碼 // private static String AUTH = FileUtil.getPropertyValue("/properties/redis.properties", "auth"); //可用連接實例的最大數目,默認值為8; //如果賦值為-1,則表示不限制;如果pool已經分配了maxActive個jedis實例,則此時pool的狀態為exhausted(耗盡)。 private static int MAX_ACTIVE = FileUtil.getPropertyValueInt( "/properties/redis.properties" , "max_active" );; //控制一個pool最多有多少個狀態為idle(空閑的)的jedis實例,默認值也是8。 private static int MAX_IDLE = FileUtil.getPropertyValueInt( "/properties/redis.properties" , "max_idle" );; //等待可用連接的最大時間,單位毫秒,默認值為-1,表示永不超時。如果超過等待時間,則直接拋出JedisConnectionException; private static int MAX_WAIT = FileUtil.getPropertyValueInt( "/properties/redis.properties" , "max_wait" );; //超時時間 private static int TIMEOUT = FileUtil.getPropertyValueInt( "/properties/redis.properties" , "timeout" );; //在borrow一個jedis實例時,是否提前進行validate操作;如果為true,則得到的jedis實例均是可用的; private static boolean TEST_ON_BORROW = FileUtil.getPropertyValueBoolean( "/properties/redis.properties" , "test_on_borrow" );; private static JedisPool jedisPool = null ; /** * redis過期時間,以秒為單位 */ public final static int EXRP_HOUR = 60 * 60 ; //一小時 public final static int EXRP_DAY = 60 * 60 * 24 ; //一天 public final static int EXRP_MONTH = 60 * 60 * 24 * 30 ; //一個月 /** * 初始化Redis連接池 */ private static void initialPool(){ try { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(MAX_ACTIVE); config.setMaxIdle(MAX_IDLE); config.setMaxWaitMillis(MAX_WAIT); config.setTestOnBorrow(TEST_ON_BORROW); jedisPool = new JedisPool(config, ADDR_ARRAY.split( "," )[ 0 ], PORT, TIMEOUT); } catch (Exception e) { logger.error( "First create JedisPool error : " +e); try { //如果第一個IP異常,則訪問第二個IP JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(MAX_ACTIVE); config.setMaxIdle(MAX_IDLE); config.setMaxWaitMillis(MAX_WAIT); config.setTestOnBorrow(TEST_ON_BORROW); jedisPool = new JedisPool(config, ADDR_ARRAY.split( "," )[ 1 ], PORT, TIMEOUT); } catch (Exception e2){ logger.error( "Second create JedisPool error : " +e2); } } } /** * 在多線程環境同步初始化 */ private static void poolInit() { //斷言 ,當前鎖是否已經鎖住,如果鎖住了,就啥也不干,沒鎖的話就執行下面步驟 assert ! lockPool.isHeldByCurrentThread(); lockPool.lock(); try { if (jedisPool == null ) { initialPool(); } } catch (Exception e){ e.printStackTrace(); } finally { lockPool.unlock(); } } public static Jedis getJedis() { //斷言 ,當前鎖是否已經鎖住,如果鎖住了,就啥也不干,沒鎖的話就執行下面步驟 assert ! lockJedis.isHeldByCurrentThread(); lockJedis.lock(); if (jedisPool == null ) { poolInit(); } Jedis jedis = null ; try { if (jedisPool != null ) { jedis = jedisPool.getResource(); } } catch (Exception e) { logger.error( "Get jedis error : " +e); } finally { returnResource(jedis); lockJedis.unlock(); } return jedis; } /** * 釋放jedis資源 * @param jedis */ public static void returnResource( final Jedis jedis) { if (jedis != null && jedisPool != null ) { jedisPool.returnResource(jedis); } } /** * 設置 String * @param key * @param value */ public synchronized static void setString(String key ,String value){ try { value = StringUtil.isEmpty(value) ? "" : value; getJedis().set(key,value); } catch (Exception e) { logger.error( "Set key error : " +e); } } /** * 設置 過期時間 * @param key * @param seconds 以秒為單位 * @param value */ public synchronized static void setString(String key , int seconds,String value){ try { value = StringUtil.isEmpty(value) ? "" : value; getJedis().setex(key, seconds, value); } catch (Exception e) { logger.error( "Set keyex error : " +e); } } /** * 獲取String值 * @param key * @return value */ public synchronized static String getString(String key){ if (getJedis() == null || !getJedis().exists(key)){ return null ; } return getJedis().get(key); } } |
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:http://blog.csdn.net/tuposky/article/details/45340183