zoukankan      html  css  js  c++  java
  • 并发问题解决小结

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

    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
  • 相关阅读:
    Effective Java 第三版——72. 赞成使用标准异常
    Effective Java 第三版——71. 避免不必要地使用检查异常
    Effective Java 第三版——70. 对可恢复条件使用检查异常,对编程错误使用运行时异常
    Effective Java 第三版——69. 仅在发生异常的条件下使用异常
    Effective Java 第三版——68. 遵守普遍接受的命名约定
    Effective Java 第三版——67. 明智谨慎地进行优化
    Effective Java 第三版——66. 明智谨慎地使用本地方法
    Effective Java 第三版——65. 接口优于反射
    Effective Java 第三版——64. 通过对象的接口引用对象
    Effective Java 第三版——63. 注意字符串连接的性能
  • 原文地址:https://www.cnblogs.com/handsomecui/p/9235430.html
Copyright © 2011-2022 走看看