Some temporary data is often cached because of business needs. For example: Mobile phone number to send a verification code, 60s within the same phone number can not be repeated to send verification code. Check flight information, cache 1 minutes of popular query data ....
Using Redis as a data cache has been simple and convenient. But if it is a small app, the data is not so big, you may need to cache less than 100KB of data, using Redis is overqualified
A recent project on the line, the boss told me: "Really need to use Redis?" No, just delete it first. I think about it, because the app entrance has two IP, different machines, although the volume of business, in order to share the session, or on the
If there is only one entry (there is no data sharing problem), the volume of business is still small, or the temporary map is better.
Refer to the Apache Storme Project Timecachemap and Rotatingmap, extract their own convenient available temporary map container, the name is called Rotatingcachemap.
Based on jdk1.8, the old project is estimated to be less than ... Send a timecachemap and Rotatingmap source Analysis http://www.cnblogs.com/yanghuahui/p/3677117.html
Packagecom.tianjixie.timcross.utils;Importjava.time.Instant;ImportJava.util.HashMap;/*** Temporary data container * data storage using HASHMAP Array (Recycle bucket) * *@authorTimcross*/ Public classRotatingcachemap<k, v> { //Default work Map (Recycle Bin) cannot be less than 3 (to ensure minimum work map number > 1) Private Static Final intMin_bucket_num = 3; //Maximum Capacity Private Static Final intMaximum_size = 10000; //default timeout (Recycle) time (seconds) Private Static Final intRotate_time = 60 * 60 * 10; //default Recycle Check frequency (ms) Private Static Final intSleep_time = 60 * 1000; //bucket Map Initialization capacity Private Final int_mapinitcapacity; //Bucket Map Initialize percentage of expansion Private Final float_maploadfactor; //time-out (seconds) Private Final Long_rotatetime; //Bucket Max Index Private Final int_bucketsmaxindex; //Pending Delete Data check method call (default NULL, no data check) Private FinalCheckremovedata<k, v>_checkremove; //all elements Key: element add time Private FinalHashmap<k, object[]> _addtime =NewHashmap<k, object[]>(); //Recycle Bucket Collection PrivateHashmap<k, v>[] _buckets; //last (bucket) payback time Private Long_lastrotate =Getnowsecend (); PublicRotatingcachemap () { This(Min_bucket_num, Rotate_time, Sleep_time,NULL, 0.8f); } /** * @paramBucketnum The number of maps (Data | Recycle bins) working simultaneously defaults to 3 *@paramrotatetime Time-out (seconds) default 60*60*10 (10 hours) *@paramsleeptime Recovery thread scan interval (milliseconds) default 60000 (1 minutes) *@paramcheckremovedate to delete data check default null (do not use data check) *@parammapinitcapacity default New data map size *@parammaploadfactor default New data map re-hash required percentage*/ PublicRotatingcachemap (intBucketnum,LongRotatetime,LongSleeptime, Checkremovedata<k, v>Checkremovedate,intMapinitcapacity,floatmaploadfactor) {_maploadfactor=Maploadfactor; _mapinitcapacity=mapinitcapacity; _checkremove=checkremovedate; _rotatetime=Rotatetime; _bucketsmaxindex= BucketNum-1; //Calculate bucket position change time, FIFO LongExpiretime = rotatetime/bucketnum + 1; if(Bucketnum < min_bucket_num) Bucketnum =Min_bucket_num; _buckets=NewHashmap[bucketnum]; for(inti = 0; i < Bucketnum; i++) {_buckets[i]=NewHashmap<>(mapinitcapacity, maploadfactor); } //start data time-out recycle threadThread _cleaner =NewThread (() { while(true) { Try{Thread.CurrentThread (). Sleep (Sleeptime); } Catch(Interruptedexception ex) {}Longnow =Getnowsecend (); //detecting bucket position change time and storage maximum capacity if(now-_lastrotate > Expiretime | | size () >maximum_size) { //Start Data Cleanup NewThread (()rotate ()). Start (); _lastrotate=Now ; } } }); _cleaner.setdaemon (true); _cleaner.start (); } Public BooleanContainsKey (K key) {object[] addtime=_addtime.get (key); if(Addtime = =NULL)return false; if((Instant.now (). Getepochsecond ()-(Long) addtime[0]) >_rotatetime) { //data has timed outremove (key); return false; } return true; } Public intsize () {return_addtime.size (); } PublicV get (K key) {object[] addtime=_addtime.get (key); if(Addtime = =NULL)return NULL; if((Instant.now (). Getepochsecond ()-(Long) addtime[0]) >_rotatetime) { //data has timed outremove (key); return NULL; } return(Hashmap<k, v>) addtime[1]). Get (key); } Public voidput (K key, V value) {object[] objects=NewObject[2]; objects[0] =Getnowsecend (); objects[1] = _buckets[0]; ((HASHMAP) objects[1]). Put (key, value); Object[] Lastput=_addtime.get (key); _addtime.put (key, objects); if(Lastput! =NULL&& lastput[1]! = Objects[1]) ((HASHMAP) lastput[1]). Remove (key); //Check that the total amount of data is too large if(Size () > Maximum_size)NewThread (()rotate ()). Start (); } Public voidRemove (K key) {object[] Remove=_addtime.remove (key); if(Remove! =NULL) ((HASHMAP) remove[1]). Remove (key); } Public voidUpdate (K key) {object[] update=_addtime.get (key); if(Update = =NULL)return; update[0] =Getnowsecend (); HashMap<k, v> bucket = _buckets[0]; if(update[1] = = bucket)return; V Remove= (V) ((HASHMAP) update[1]). Get (key); Bucket.put (key, remove); ((HASHMAP) update[1]). Remove (key); update[1] =buckets; } /*** Recover End barrels * Temporarily prohibit manual call * *@returndeleted map (Recycle Bin)*/ Private voidrotate () {HashMap<k, v>Deadmap; Deadmap=_buckets[_bucketsmaxindex]; Hashmap[] Hashmaps=NewHashmap[_buckets.length]; hashmaps[0] =NewHashMap ((_mapinitcapacity + _buckets[0].size ())/2, _maploadfactor); for(inti = 0; i < _bucketsmaxindex; i++) {hashmaps[i+ 1] =_buckets[i]; } deadmap.keyset (). Stream (). ForEach (Key-{object[] Remove=_addtime.remove (key); if(remove[1]! =deadmap) _addtime.put (key, remove); if(_checkremove! =NULL) _checkremove.check (Key, Deadmap.get (key)); }); //return deadmap; } /*** Get Current time * *@returnseconds*/ Private LongGetnowsecend () {returnInstant.now (). Getepochsecond (); } /*** Data Check interface * *@param<K> Pending Delete key *@param<V> Pending Delete value*/ Public InterfaceCheckremovedata<k, v> { voidCheck (K key, V val); }}
Simple-to-use temporary map container (refer to Timecachemap and Rotatingmap)