多线程并发获取订单号

[b]使用倒计数器(信号量)重现高并发场景:[/b]

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重复了,存在线程不安全

[b]解决方案[/b]
[b]同步锁[/b]
http://blog.csdn.net/lianqiangjava/article/details/12652201/
http://bbs.csdn.net/topics/390868532
[b]同步代码块:[/b]

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;
}

[b]lock锁[/b],比较灵活
异常时,无法解锁,需要在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万并发,
锁失效时间难设置,容易死锁
不可重写
[url]http://blog.csdn.net/fansunion/article/details/52302650[/url]

3.基于zookeeper实现分布式锁
实现相对简单
可靠性强
性能好

zk数据结构是一棵树,像Unix文件系统路径相似,每个节点存数数据。
通过客户端可以对zk增删改,可以注册watcher监控zk变化

zk节点类型:
持久节点(Persistent)
持久顺序节点(Persistent_sequential)
临时节点(Ephemeral)
临时顺序节点(Ephemeral_sequential)

对于持久节点和临时节点,同一zk下,节点的名称是唯一的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值