关于一次自动转单出现的并发问题的解决:
1.方案:直接用synchronized(customerId),
存在问题:可能存在坑,字符串的hashCode相同时地址不一定相同,详情见博客:https://blog.csdn.net/u014653197/article/details/76177277
详见代码:
package autoTransfer; import java.util.Scanner; /** * Created by cuijunyong on 2018/6/27. */ public class TestMain { private static AutoTransfer autoTransfer = new AutoTransfer(); private static Scanner cin = new Scanner(System.in); public static void main(String[] args) { // String a = cin.next(); // String b = cin.next(); // String c = cin.next(); new MyThread("123").start(); new MyThread("123").start(); new MyThread(new String("123")).start(); } } class MyThread extends Thread{ private String customerId; private static AutoTransfer autoTransfer = new AutoTransfer(); @Override public void run() { try { autoTransfer.run(customerId); } catch (Exception e) { e.printStackTrace(); } } public MyThread(String customerId) { this.customerId = customerId; } }
package autoTransfer; /** * Created by cuijunyong on 2018/6/27. */ public class AutoTransfer{ public void run(String customerId) throws Exception{ synchronized (customerId){ System.out.println(Thread.currentThread() + "自动转单开始customerId=" + customerId + " hashCode=" + customerId.hashCode() + "真正内存地址=" + System.identityHashCode(customerId)); Thread.sleep(5000); System.out.println(Thread.currentThread() + "自动转单结束customerId=" + customerId + " hashCode=" + customerId.hashCode() + "真正内存地址=" + System.identityHashCode(customerId)); } } }
这个简单一点的解决方案可以直接synchronized(customerId.intern())
2.方案:用concurrentHashMap 进入用map.put(customerId)的返回值判断是否存在,如果返回值不为空,证明已经有customerId在访问,就不执行方法。方法结束时remove掉
存在问题:如果中途抛出异常会不会造成这一cuntomerId一直不会被remove掉。
3.方案:添加try{
if(map.put(customerId)!=null)return;
Dosomething();
}catch(){
}
finally{
map.remove(customerId);
}finally内remove掉
存在问题:map.put(customerId)放在了try里,会造成并发访问return掉的也执行了finally方法,下次并行就还会造成并发问题。
4.方案:于是将if(map.put(customerId)!=null)return;放到try外边
存在问题:出现异常不能被抛出去,前端获取不到异常。
5.解决方案:不用catch了直接try{}finally{}
package autoTransfer; import java.util.Scanner; /** * Created by cuijunyong on 2018/6/27. */ public class TestMain { private static AutoTransfer autoTransfer = new AutoTransfer(); private static Scanner cin = new Scanner(System.in); public static void main(String[] args) { // String a = cin.next(); // String b = cin.next(); // String c = cin.next(); new MyThread("123").start(); new MyThread("123").start(); new MyThread(new String("123")).start(); } } class MyThread extends Thread{ private String customerId; private static AutoTransfer autoTransfer = new AutoTransfer(); @Override public void run() { try { autoTransfer.run(customerId); } catch (Exception e) { e.printStackTrace(); } } public MyThread(String customerId) { this.customerId = customerId; } }
package autoTransfer; import java.util.concurrent.ConcurrentHashMap; /** * Created by cuijunyong on 2018/6/27. */ public class AutoTransfer{ private ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); public void run(String customerId) throws Exception{ if(map.put(customerId, 1) != null){ return; } try { System.out.println(Thread.currentThread() + "自动转单开始customerId=" + customerId + " hashCode=" + customerId.hashCode() + "真正内存地址=" + System.identityHashCode(customerId)); Thread.sleep(5000); System.out.println(Thread.currentThread() + "自动转单结束customerId=" + customerId + " hashCode=" + customerId.hashCode() + "真正内存地址=" + System.identityHashCode(customerId)); }finally { map.remove(customerId); } } }