并发问题解决小结

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

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
posted @ 2018-06-27 18:27  handsomecui  阅读(746)  评论(0编辑  收藏  举报