併發問題解決小結

關於一次自動轉單出現的併發問題的解決:前端

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())java

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
相關文章
相關標籤/搜索