• 并发问题解决小结


    关于一次自动转单出现的并发问题的解决:

    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;
      }
    }
    View Code
    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));
        }
      }
    
    }
    View Code

    这个简单一点的解决方案可以直接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;
      }
    }
    View Code
    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);
        }
    
      }
    
    }
    View Code
  • 相关阅读:
    【推荐】com.alibaba方式xml转json,能将xml的所有属性方法,全部转化为json
    关于使用JAXB读取xml文档转换为java对象报错:类的两个属性具有相同名称com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsExc...
    java正则,将<a或者</a,尖括号后面的字母改成大写
    javaben转xml
    三次握手四次挥手
    RPC接口测试(六)RPC协议解析(重要!重要!重要!)
    os.popen(cmd) 与 os.system(cmd) 的区别
    jmeter测试webSocket接口
    Ubuntu20.04 体验和美化
    API可视化管理平台YApi
  • 原文地址:https://www.cnblogs.com/handsomecui/p/9235430.html
Copyright © 2020-2023  润新知