直接使用String做同步锁,会发现不好使。 因为,只有常量池里的字符串(比如代码里直接赋值的),相同值才会返回同一个对象。 使用intern()又感觉有些浪费。
package com.example.demo.util;
import java.io.File; import java.io.IOException; import java.util.concurrent.TimeUnit;
import org.apache.commons.io.FileUtils;
import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder;
public class OSSUtil2 {
/** * (缓存一分钟就过期). */ private static Cache<String, Object> fileCache = CacheBuilder.newBuilder().expireAfterAccess(1, TimeUnit.MINUTES) .build();
private OSSUtil2() { }
public static void img() throws IOException { File file = new File("D:\\example-resize.jpg");
for (int aa = 0; aa < 10; aa++) { final int x = aa; new Thread() { public void run() { currentThread().setName("" + x); for (int i = 0; i < 10; i++) {
// 按文件,分别做同步锁 String key = file.getAbsolutePath();
// 怕字符串不靠谱,使用对应的Object锁
// 如果不存在(新的entry),那么会向map中添加该键值对,并返回null。 // 如果已经存在,那么不会覆盖已有的值,直接返回已经存在的值。 Object lock = null; Object newLock = new Object(); Object oldLock = fileCache.asMap().putIfAbsent(key, newLock); if (oldLock == null) { lock = newLock; } else { lock = oldLock; }
synchronized (lock) {
System.out.println("开始处理图片:" + Thread.currentThread().getName()); // if (file.exists()) { // System.out.println("图片存在,直接返回" + Thread.currentThread().getName()); // return; // } // GetObjectRequest request = new GetObjectRequest(bucketName, path); // request.setProcess(style); // File fileTemp = new File( // file.getAbsolutePath() + System.currentTimeMillis() + random.nextInt(10000)); // ossClient.getObject(request, file); // fileTemp.renameTo(file);
try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("结束处理图片:" + Thread.currentThread().getName()); }
} } }.start(); }
// new Thread() { // public void run() { // while(true) { // String hex = null; // try { // hex = getFileHex(file); // System.out.println(hex.length()); // if (hex.contains("0000000000000000000000000")) { // System.out.println("NG"); // System.exit(0); // } else { // System.out.println("OK"); // } // } catch (IOException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // try { // Thread.sleep(10); // } catch (InterruptedException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // } // } // }.start();
}
public static String getFileHex(File file) throws IOException { StringBuilder sb = new StringBuilder(); byte[] byteArray = FileUtils.readFileToByteArray(file); for (byte b : byteArray) { int v = b; if (v < 0) { v = v + 256; } String hex = Integer.toHexString(v).toUpperCase(); if (hex.length() == 1) { hex = "0" + hex; } sb.append(hex); } return sb.toString(); }
public static void main(String[] args) { try { OSSUtil2.img(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }
new Thread() { public void run() { while (true) { System.out.println("size:" + fileCache.size()); try { Thread.sleep(200); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
} }.start();
try { Thread.sleep(60000 * 5); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } File file = new File("D:\\example-resize.jpg"); System.out.println("map:" + fileCache.getIfPresent(file.getAbsolutePath()));
} }
注意点: (1)Cache使用expireAfterAccess,一段时间没有访问后才释放。 不要使用expireAfterWrite,这个写入值,到时间就会释放,会导致同步锁失效。
(2)使用fileCache.asMap().putIfAbsent(key, newLock)来处理并发写入。
(3)google Cache处理过期值,不是单独线程处理的,是后面访问时,顺带处理的。 如果一直没有请求,也就不会删掉失效的key
|