package com.baozun.trade; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.CountDownLatch; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class OrderTest implements Runnable { private Logger log = LoggerFactory.getLogger(OrderTest.class); private static final int MUN = 10; // 锁,信号量(jkd包倒计数器),事件机制 private static CountDownLatch cdl = new CountDownLatch(MUN); private static Lock lock = new ReentrantLock(); private static int i =0; public void createOrder() { String orderCode = getOrderCode(); // lock.lock(); log.info(Thread.currentThread().getName()+" ========" + orderCode); } public void run() { try { // 等待其他9个线程初始化完成 cdl.await(); } catch(InterruptedException e) { e.printStackTrace(); } createOrder(); } public static void main(String[] args) throws InterruptedException{ // TODO Auto-generated method stub for(int i =1; i <= MUN; i++) { new Thread(new OrderTest()).start(); cdl.countDown(); } Thread.currentThread().sleep(3000); } private String getOrderCode() { Date now = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.format(now) +":" + ++i; } }
运行结果:
2017-12-20 19:53:42.929 [Thread-1] INFO OrderTest.java:28 com.baozun.trade.OrderTest -Thread-1 ========2017-12-20 19:53:42:1 2017-12-20 19:53:42.929 [Thread-7] INFO OrderTest.java:28 com.baozun.trade.OrderTest -Thread-7 ========2017-12-20 19:53:42:3 2017-12-20 19:53:42.929 [Thread-2] INFO OrderTest.java:28 com.baozun.trade.OrderTest -Thread-2 ========2017-12-20 19:53:42:6 2017-12-20 19:53:42.929 [Thread-4] INFO OrderTest.java:28 com.baozun.trade.OrderTest -Thread-4 ========2017-12-20 19:53:42:5 2017-12-20 19:53:42.929 [Thread-3] INFO OrderTest.java:28 com.baozun.trade.OrderTest -Thread-3 ========2017-12-20 19:53:42:8 2017-12-20 19:53:42.929 [Thread-9] INFO OrderTest.java:28 com.baozun.trade.OrderTest -Thread-9 ========2017-12-20 19:53:42:9 2017-12-20 19:53:42.929 [Thread-5] INFO OrderTest.java:28 com.baozun.trade.OrderTest -Thread-5 ========2017-12-20 19:53:42:4 2017-12-20 19:53:42.929 [Thread-6] INFO OrderTest.java:28 com.baozun.trade.OrderTest -Thread-6 ========2017-12-20 19:53:42:2 2017-12-20 19:53:42.929 [Thread-8] INFO OrderTest.java:28 com.baozun.trade.OrderTest -Thread-8 ========2017-12-20 19:53:42:2 2017-12-20 19:53:42.929 [Thread-0] INFO OrderTest.java:28 com.baozun.trade.OrderTest -Thread-0 ========2017-12-20 19:53:42:7
发现订单号2重复了,存在线程不安全
解决方案
同步锁
http://blog.csdn.net/lianqiangjava/article/details/12652201/
http://bbs.csdn.net/topics/390868532
同步代码块:
private String getOrderCode() { String orderCode = ""; synchronized (this){ Date now = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); orderCode = sdf.format(now) +":" + ++i; } return orderCode; }或 private synchronized String getOrderCode() { String orderCode = ""; Date now = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); orderCode = sdf.format(now) +":" + ++i; return orderCode;
以上会发现是无效的,原因是new了五个实例,有五个内存地址不能共享。
private static synchronized String getOrderCode() { String orderCode = ""; synchronized (this){ Date now = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); orderCode = sdf.format(now) +":" + ++i; } return orderCode; }
lock锁,比较灵活
异常时,无法解锁,需要在finally里加锁避免死锁。
让每个线程进锁。
public void createOrder() { lock.lock(); try { String orderCode = getOrderCode(); log.info(Thread.currentThread().getName()+" ========" + orderCode); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } }
分布式锁实现技术:
写表数据,表由唯一主键,每个线程有唯一建同时插入,只有一个线程插入成功,然后解锁(再找数据删除掉)。
1.基于数据库实现分布式锁
mysql最大并发峰值1000,
锁没有失效时间,容易死锁
非阻塞式的
不可重入
2.缓存实现分布式锁
轻轻松松响应10万并发,
锁失效时间难设置,容易死锁
不可重写
http://blog.csdn.net/fansunion/article/details/52302650
3.基于zookeeper实现分布式锁
实现相对简单
可靠性强
性能好
zk数据结构是一棵树,像Unix文件系统路径相似,每个节点存数数据。
通过客户端可以对zk增删改,可以注册watcher监控zk变化
zk节点类型:
持久节点(Persistent)
持久顺序节点(Persistent_sequential)
临时节点(Ephemeral)
临时顺序节点(Ephemeral_sequential)
对于持久节点和临时节点,同一zk下,节点的名称是唯一的。