成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

面試官:你是如何使用JDK來實現自己的緩存(支持高并發)?

開發 架構 后端
只是在單線程或者多線程間作數據緩存,其實完全可以自己手寫一個緩存工具。下面就來簡單實現一個這樣的工具。

[[267393]]

需求分析

項目中經常會遇到這種場景:一份數據需要在多處共享,有些數據還有時效性,過期自動失效。比如手機驗證碼,發送之后需要緩存起來,然后處于安全性考慮,一般還要設置有效期,到期自動失效。我們怎么實現這樣的功能呢?

解決方案

  1.  使用現有的緩存技術框架,比如redis,ehcache。優點:成熟,穩定,功能強大;缺點,項目需要引入對應的框架,不夠輕量。
  2.  如果不考慮分布式,只是在單線程或者多線程間作數據緩存,其實完全可以自己手寫一個緩存工具。下面就來簡單實現一個這樣的工具。

先上代碼: 

  1. import java.util.HashMap;  
  2. import java.util.Map;  
  3. import java.util.concurrent.*;  
  4. /**  
  5.  * @Author: lixk  
  6.  * @Date: 2018/5/9 15:03  
  7.  * @Description: 簡單的內存緩存工具類  
  8.  */  
  9. public class Cache {  
  10.  //鍵值對集合  
  11.  private final static Map<String, Entity> map = new HashMap<>();  
  12.  //定時器線程池,用于清除過期緩存  
  13.  private final static ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();  
  14.  /**  
  15.  * 添加緩存  
  16.  *  
  17.  * @param key 鍵  
  18.  * @param data 值  
  19.  */  
  20.  public synchronized static void put(String key, Object data) {  
  21.  Cache.put(key, data, 0);  
  22.  }  
  23.  /**  
  24.  * 添加緩存  
  25.  *  
  26.  * @param key 鍵  
  27.  * @param data 值  
  28.  * @param expire 過期時間,單位:毫秒, 0表示***長  
  29.  */  
  30.  public synchronized static void put(String key, Object data, long expire) {  
  31.  //清除原鍵值對  
  32.  Cache.remove(key);  
  33.  //設置過期時間  
  34.  if (expire > 0) {  
  35.  Future future = executor.schedule(new Runnable() {  
  36.  @Override  
  37.  public void run() {  
  38.  //過期后清除該鍵值對  
  39.  synchronized (Cache.class) {  
  40.  map.remove(key);  
  41.  }  
  42.  }  
  43.  }, expire, TimeUnit.MILLISECONDS);  
  44.  map.put(key, new Entity(data, future));  
  45.  } else {  
  46.  //不設置過期時間  
  47.  map.put(key, new Entity(data, null));  
  48.  }  
  49.  }  
  50.  /**  
  51.  * 讀取緩存  
  52.  *  
  53.  * @param key 鍵  
  54.  * @return  
  55.  */  
  56.  public synchronized static Object get(String key) {  
  57.  Entity entity = map.get(key);  
  58.  return entity == null ? null : entity.getValue();  
  59.  }  
  60.  /**  
  61.  * 讀取緩存  
  62.  *  
  63.  * @param key 鍵  
  64.  * * @param clazz 值類型  
  65.  * @return  
  66.  */  
  67.  public synchronized static <T> T get(String key, Class<T> clazz) {  
  68.  return clazz.cast(Cache.get(key));  
  69.  }  
  70.  /**  
  71.  * 清除緩存  
  72.  *  
  73.  * @param key  
  74.  * @return  
  75.  */  
  76.  public synchronized static Object remove(String key) {  
  77.  //清除原緩存數據  
  78.  Entity entity = map.remove(key);  
  79.  if (entity == null) return null;  
  80.  //清除原鍵值對定時器  
  81.  Future future = entity.getFuture();  
  82.  if (future != null) future.cancel(true);  
  83.  return entity.getValue();  
  84.  }  
  85.  /**  
  86.  * 查詢當前緩存的鍵值對數量  
  87.  *  
  88.  * @return  
  89.  */  
  90.  public synchronized static int size() {  
  91.  return map.size();  
  92.  }  
  93.  /**  
  94.  * 緩存實體類  
  95.  */  
  96.  private static class Entity {  
  97.  //鍵值對的value  
  98.  private Object value;  
  99.  //定時器Future   
  100.  private Future future;  
  101.  public Entity(Object value, Future future) {  
  102.  this.value = value;  
  103.  this.future = future;  
  104.  }  
  105.  /**  
  106.  * 獲取值  
  107.  *  
  108.  * @return  
  109.  */  
  110.  public Object getValue() {  
  111.  return value;  
  112.  }  
  113.  /**  
  114.  * 獲取Future對象  
  115.  *  
  116.  * @return  
  117.  */  
  118.  public Future getFuture() {  
  119.  return future;  
  120.  }  
  121.  }  

本工具類主要采用 HashMap+定時器線程池 實現,map 用于存儲鍵值對數據,map的value是 Cache 的內部類對象 Entity,Entity 包含 value 和該鍵值對的生命周期定時器 Future。Cache 類對外只提供了 put(key, value), put(key, value, expire), get(key), get(key, class), remove(key), size()幾個同步方法。

當添加鍵值對數據的時候,首先會調用remove()方法,清除掉原來相同 key 的數據,并取消對應的定時清除任務,然后添加新數據到 map 中,并且,如果設置了有效時間,則添加對應的定時清除任務到定時器線程池。

測試 

  1. import java.util.concurrent.ExecutionException;  
  2. import java.util.concurrent.ExecutorService;  
  3. import java.util.concurrent.Executors;  
  4. import java.util.concurrent.Future;  
  5. /**  
  6.  * @Author: lixk  
  7.  * @Date: 2018/5/9 16:40  
  8.  * @Description: 緩存工具類測試  
  9.  */  
  10. public class CacheTest {  
  11.  /**  
  12.  * 測試  
  13.  *  
  14.  * @param args  
  15.  */  
  16.  public static void main(String[] args) throws InterruptedException, ExecutionException {  
  17.  String key = "id" 
  18.  //不設置過期時間  
  19.  System.out.println("***********不設置過期時間**********");  
  20.  Cache.put(key, 123);  
  21.  System.out.println("key:" + key + ", value:" + Cache.get(key));  
  22.  System.out.println("key:" + key + ", value:" + Cache.remove(key));  
  23.  System.out.println("key:" + key + ", value:" + Cache.get(key));  
  24.  //設置過期時間  
  25.  System.out.println("  
  26. ***********設置過期時間**********");  
  27.  Cache.put(key, "123456", 1000);  
  28.  System.out.println("key:" + key + ", value:" + Cache.get(key));  
  29.  Thread.sleep(2000);  
  30.  System.out.println("key:" + key + ", value:" + Cache.get(key));  
  31.  /******************并發性能測試************/  
  32.  System.out.println("  
  33. ***********并發性能測試************");  
  34.  //創建有10個線程的線程池,將1000000次操作分10次添加到線程池  
  35.  ExecutorService executorService = Executors.newFixedThreadPool(10);  
  36.  Future[] futures = new Future[10];  
  37.  /********添加********/  
  38.  {  
  39.  long start = System.currentTimeMillis();  
  40.  for (int j = 0; j < 10; j++) {  
  41.  futures[j] = executorService.submit(() -> {  
  42.  for (int i = 0; i < 100000; i++) {  
  43.  Cache.put(Thread.currentThread().getId() + key + i, i, 300000);  
  44.  }  
  45.  });  
  46.  }  
  47.  //等待全部線程執行完成,打印執行時間  
  48.  for (Future future : futures) {  
  49.  future.get();  
  50.  }  
  51.  System.out.printf("添加耗時:%dms  
  52. ", System.currentTimeMillis() - start);  
  53.  }  
  54.  /********查詢********/  
  55.  {  
  56.  long start = System.currentTimeMillis();  
  57.  for (int j = 0; j < 10; j++) {  
  58.  futures[j] = executorService.submit(() -> {  
  59.  for (int i = 0; i < 100000; i++) {  
  60.  Cache.get(Thread.currentThread().getId() + key + i);  
  61.  }  
  62.  });  
  63.  }  
  64.  //等待全部線程執行完成,打印執行時間  
  65.  for (Future future : futures) {  
  66.  future.get();  
  67.  }  
  68.  System.out.printf("查詢耗時:%dms  
  69. ", System.currentTimeMillis() - start);  
  70.  }  
  71.  System.out.println("當前緩存容量:" + Cache.size());  
  72.  }  

測試結果: 

  1. ***********不設置過期時間**********  
  2. key:id, value:123  
  3. key:id, value:123  
  4. key:id, value:null  
  5. ***********設置過期時間**********  
  6. key:id, value:123456  
  7. key:id, value:null  
  8. ***********并發性能測試************  
  9. 添加耗時:2313ms  
  10. 查詢耗時:335ms  
  11. 當前緩存容量:1000000 

測試程序使用有10個線程的線程池來模擬并發,總共執行一百萬次添加和查詢操作,時間大約都在兩秒多,表現還不錯,每秒40萬讀寫并發應該還是可以滿足大多數高并發場景的^_^ 

責任編輯:龐桂玉 來源: 今日頭條
相關推薦

2025-03-10 11:48:22

項目服務設計

2024-02-20 14:10:55

系統緩存冗余

2025-02-26 12:19:52

2015-08-13 10:29:12

面試面試官

2024-01-19 14:03:59

Redis緩存系統Spring

2021-05-08 08:35:33

Webpack前端性能

2024-05-11 15:11:44

系統軟件部署

2023-10-28 09:13:32

系統面試官架構

2024-02-04 10:08:34

2024-12-25 15:44:15

2022-02-14 20:53:33

開源庫開發代碼

2023-12-19 09:24:22

LinuxBIOSUEFI

2024-11-08 13:36:09

2023-12-06 13:38:00

Redis緩存穿透緩存擊穿

2024-03-12 10:44:42

2020-10-26 07:07:50

線程安全框架

2024-10-15 10:00:06

2020-10-15 06:26:24

高并發場景冰河

2023-11-27 08:17:05

SpringJava

2025-04-29 02:00:00

高并發系統場景
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产91丝袜 | 欧美全黄| 黄色男女网站 | 成人黄视频在线观看 | 国产欧美一区二区三区在线看 | 人人做人人澡人人爽欧美 | 日本精品久久久久久久 | 三a毛片| 成人黄色电影在线播放 | 国产精品免费福利 | 91天堂| 欧美一区视频 | 黄色网址大全在线观看 | 国产成人一区二区 | 国产成人精品999在线观看 | 亚洲精品一区二区冲田杏梨 | 极品销魂美女一区二区 | 亚洲资源站| 在线2区 | www久久久 | 亚洲精品久久久久中文字幕欢迎你 | 亚洲精品粉嫩美女一区 | 亚洲一区二区在线视频 | 美女激情av | 黄色网页在线观看 | 国产欧美在线观看 | 国产真实精品久久二三区 | 亚洲精品成人免费 | 五月网婷婷 | 欧美精品一二三 | 国产精品视频网 | 欧美成人一区二区三区 | 国产91丝袜在线播放 | 一区二区三区免费观看 | 国产视频中文字幕 | 四虎成人免费电影 | 色呦呦在线 | 嫩草最新网址 | 国产精品久久国产精品99 | 色综合久久久久 | 草久在线视频 |