| | |
| | | import java.util.Date; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | |
| | | @Service |
| | |
| | | } |
| | | } |
| | | |
| | | private static String lastResult = null; |
| | | private static long lastExecuteTime = 0; |
| | | private static class CacheEntry { |
| | | String result; |
| | | long lastExecuteTime; |
| | | } |
| | | |
| | | private static final Map<String, CacheEntry> cacheMap = new ConcurrentHashMap<>(); |
| | | private static final long MIN_INTERVAL_MS = 3000; |
| | | private static final Object cacheLock = new Object(); |
| | | private static final Object globalLock = new Object(); |
| | | |
| | | public static String doGet(String pid) { |
| | | long currentTime = System.currentTimeMillis(); |
| | | |
| | | // 第一次快速检查(不加锁) |
| | | if (lastResult != null && (currentTime - lastExecuteTime) < MIN_INTERVAL_MS) { |
| | | return lastResult; |
| | | // 1. 先检查该pid是否有缓存 |
| | | CacheEntry entry = cacheMap.get(pid); |
| | | if (entry != null && (currentTime - entry.lastExecuteTime) < MIN_INTERVAL_MS) { |
| | | return entry.result; |
| | | } |
| | | |
| | | // 同步块内再次检查并执行 |
| | | synchronized (cacheLock) { |
| | | // 2. 使用双重检查锁定更新缓存 |
| | | synchronized (getLockForPid(pid)) { |
| | | currentTime = System.currentTimeMillis(); |
| | | if (lastResult != null && (currentTime - lastExecuteTime) < MIN_INTERVAL_MS) { |
| | | return lastResult; |
| | | entry = cacheMap.get(pid); |
| | | |
| | | if (entry != null && (currentTime - entry.lastExecuteTime) < MIN_INTERVAL_MS) { |
| | | return entry.result; |
| | | } |
| | | |
| | | // 执行POST请求 |
| | | // 3. 执行实际请求 |
| | | String newResult = doActualPost(pid); |
| | | |
| | | // 更新缓存 |
| | | lastResult = newResult; |
| | | lastExecuteTime = System.currentTimeMillis(); |
| | | // 4. 更新该pid的缓存 |
| | | CacheEntry newEntry = new CacheEntry(); |
| | | newEntry.result = newResult; |
| | | newEntry.lastExecuteTime = System.currentTimeMillis(); |
| | | cacheMap.put(pid, newEntry); |
| | | |
| | | return newResult; |
| | | } |
| | | } |
| | | |
| | | // 为每个pid提供独立的锁对象,避免不同pid间的阻塞 |
| | | private static final Map<String, Object> pidLocks = new ConcurrentHashMap<>(); |
| | | |
| | | private static Object getLockForPid(String pid) { |
| | | return pidLocks.computeIfAbsent(pid, k -> new Object()); |
| | | } |
| | | |
| | | |
| | | private static String doActualPost(String pid) { |
| | | String apiUrl = PropertiesUtil.getProperty("JS_IN_HTTP_URL") + "stock?key=" + PropertiesUtil.getProperty("JS_IN_KEY"); |
| | | String apiUrl = PropertiesUtil.getProperty("JS_IN_HTTP_URL") + |
| | | "stock?key=" + PropertiesUtil.getProperty("JS_IN_KEY"); |
| | | |
| | | try { |
| | | URL url = new URL(apiUrl); |
| | |
| | | } |
| | | |
| | | // 读取响应 |
| | | BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); |
| | | BufferedReader in = new BufferedReader( |
| | | new InputStreamReader(connection.getInputStream())); |
| | | String inputLine; |
| | | StringBuilder response = new StringBuilder(); |
| | | |
| | |
| | | |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | // 返回缓存或错误信息 |
| | | if (lastResult != null) { |
| | | return lastResult; |
| | | // 如果请求失败,返回该pid的旧缓存(如果有) |
| | | CacheEntry oldEntry = cacheMap.get(pid); |
| | | if (oldEntry != null && oldEntry.result != null) { |
| | | return oldEntry.result; |
| | | } |
| | | return "{\"error\":\"请求失败:" + e.getMessage() + "\"}"; |
| | | } |