`

多线程并发获取订单号

 
阅读更多
使用倒计数器(信号量)重现高并发场景:
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下,节点的名称是唯一的。




分享到:
评论

相关推荐

    JAVA生成订单号(日期+流水号)

    2. **流水号**:生成流水号通常需要一个全局变量,如原子整型(`AtomicInteger`),以保证在多线程环境中的安全性。初始化原子整型为0,每次生成订单号时自增1,然后取其值作为流水号: ```java AtomicInteger ...

    订单号的生成redis中获取

    在给定的标题“订单号的生成redis中获取”中,我们可以推断这是一个关于利用Redis来生成订单号的实践。Redis是一个高性能的键值存储系统,常用于缓存和实时数据操作,其速度快,适合处理高并发场景下的订单号生成。 ...

    并发生成重复订单号1

    - 示例中的`createOrder()`方法获取订单号后,应执行实际的订单创建逻辑,例如保存订单信息到数据库。这里仅打印了订单号,实际应用中还需要考虑数据库事务的处理,以保证数据一致性。 7. **优化建议**: - 考虑...

    java web在高并发和分布式下实现订单号生成唯一的解决方案

    在实现订单号生成唯一的解决方案中,我们需要获取线程ID、进程ID 和 MAC 地址等信息。下面是获取这些信息的代码: * 获取线程ID:`Thread.currentThread().getId()` * 获取进程ID:`ManagementFactory....

    银联订单号永远不会重复的生成算法分析与示例

    为了测试和验证这些算法,可以创建一个数据库表,将订单号字段设置为唯一键,并通过多线程并发请求生成订单号,观察是否会有重复。也可以使用Apache的ab工具进行并发压力测试。 总结来说,银联16位订单号的生成需要...

    易语言-某卡网多线程取订单号

    3. **多线程处理**:创建并启动多个线程,每个线程负责获取一个或多个订单号。 4. **线程同步**:为了防止数据冲突,可能需要用到"锁"或者"信号量"等同步机制,确保不同线程之间安全地访问共享资源。 5. **错误处理*...

    JD全自动领卷 多功能多线程全自动

    这个项目的目标是开发一个能够自动领取京东优惠券的工具,通过多线程实现高效并发,提高领券效率。 首先,我们要理解什么是自动化脚本。自动化脚本是一种预先编写好的计算机程序,它能够模拟用户在特定应用中的操作...

    Android-给集群环境下生产一定命名规范下的id如订单号等

    同时,为了适应多线程和并发场景,生成器类需要处理好线程安全问题,确保在高并发环境下也能正确生成和返回ID。 在代码实现过程中,我们可以使用Java的`synchronized`关键字或者`ReentrantLock`等锁机制来保证线程...

    高并发核心技术 - 订单与库存1

    这涉及到多个关键环节,包括下单、预占库存、支付、取消订单以及回退预占库存等。以下是对这些知识点的详细解释: 1. **下单与预占库存**: 下单过程中,为避免库存被过度占用或误减,通常会在用户下单时预占库存...

    OrderNo.rar

    这个方法应该线程安全,确保在多线程环境中不会出现冲突: ```java public class OrderNumberGenerator { private final AtomicInteger sequence; private final DateTimeFormatter formatter; public ...

    PHP秒杀系统 高并发高性能的极致挑战-

    - **乐观锁**:假设不会有并发冲突发生,在更新数据时仅在最后阶段进行版本号检查。 - **悲观锁**:假设会发生并发冲突,在操作数据前先加锁,确保数据的一致性。 在实际开发中,可以根据业务需求选择合适的锁机制...

    django多种支付、并发订单处理实例代码

    # 获取订单数据,如订单号、用户ID等 self.order_id = order_data["order_id"] self.open_id = order_data['open_id'] self.ip = order_data['ip'] # 发起支付请求... pass ``` #### 面向对象与反射 实现多...

    易语言支付宝自动充值授权

    综上所述,这个项目涵盖了易语言编程基础、第三方接口(支付宝)的集成、多线程处理、数据结构(数组)的应用以及授权逻辑的设计。对于想要深入学习易语言开发和支付接口集成的人员来说,这是一个很好的实践案例。...

    高并发下的接口幂等性解决方案.docx

    创建业务订单,一次业务请求只能创建一个,创建多个就会出大问题。 幂等性概念是指一个操作,不论执行多少次,产生的效果和返回的结果都是一样的。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得...

    Redis源码解读与项目精品设计实战

    本课程涵盖Redis设计原则及注意事项,包括Redis常见的基本指令解读,如何设计微博关系和微信朋友圈,分布式环境下全局订单号的设计,以及Redis 6.X版本中的多线程机制和核心源码分析。 在Redis中,键值对是其存储的...

    mysql取得自动增长的主键值

    - **多线程环境下的问题:** 当应用程序在多线程环境中运行时,可能会出现多个线程同时插入数据的情况,这时需要采取适当的同步机制来避免冲突。 - **性能优化:** 在高并发场景下,频繁地使用`LAST_INSERT_ID()`...

    毕设项目:基于spring+mybatis实现高并发秒杀系统,包含详细笔记.zip

    - 使用乐观锁或者分布式锁来防止秒杀时的并发问题,如使用版本号机制、Redis分布式锁等。 - 负载均衡:通过Nginx等负载均衡器,分散请求到多个后端服务器,提升系统处理能力。 - 异步处理:利用消息队列(如...

    本文在Linux平台上,以Python为开发工具,介绍12306抢票软件的基本原理.zip

    综上所述,开发一个12306抢票软件涉及了网络编程、网页解析、多线程并发、异常处理、数据库操作等多个方面,并在嵌入式Linux环境下需考虑资源优化和系统兼容性。通过合理的设计和编程,可以实现高效稳定的抢票功能。

    C#生成随机数的三种方法

     在实际应用中很多地方会用到随机数,比如需要生成的订单号.  在C#中获取随机数有三种方法:  一.Random 类  Random类默认的无参构造函数可以根据当前系统时钟为种子,进行一系列算法得出要求范围内的伪...

Global site tag (gtag.js) - Google Analytics