Java线程安全与同步代码块

因为在电商网站工作的原因,对于秒杀、闪购等促销形式相当熟悉。无外乎商家拿出一定量的库存去做所谓的“亏本买卖”,其目的是用有限的库存去吸引无限的流量。然而,我却碰到过因为系统问题,导致秒杀品超卖的情况。可怜的商户其实只提供了10双9.9元的童鞋做秒杀,却在瞬间内卖出了1000双!

类似这样的问题,在非线程安全的程序设计中十分常见,我们下面运行一个秒杀的程序:

public class SalesThread implements Runnable {
	private int stock = 10;  

    public void run() {
    		if(stock>0){
    			try{
    				Integer processingTime = new Random().nextInt(1000);
    				System.out.println(Thread.currentThread().getName() +":订单处理中...");
    				Thread.sleep(processingTime);
    				System.out.println(Thread.currentThread().getName() +
    						":交易成功,库存余量:" + --stock );
    			}catch(InterruptedException e){
    				e.printStackTrace();
    			}
    		}
    }
}
public static void main(String[] args) {
		SalesThread thread = new SalesThread();

		for(int i=0;i<30;i++)
		{
		new Thread(thread,"client-"+i+1).start();
		}
	}

我们试图使用线程类内部的stock>0来限制10个库存的销售量,但实际运行结果却是如下...每个人都买到了我的秒杀品!赔死了!心塞塞!

client-01:订单处理中...
client-11:订单处理中...
client-31:订单处理中...
client-21:订单处理中...
client-51:订单处理中...
client-41:订单处理中...
client-61:订单处理中...
client-71:订单处理中...
client-91:订单处理中...
client-81:订单处理中...
client-101:订单处理中...
client-111:订单处理中...
client-131:订单处理中...
client-121:订单处理中...
client-141:订单处理中...
client-151:订单处理中...
client-161:订单处理中...
client-171:订单处理中...
client-191:订单处理中...
client-181:订单处理中...
client-201:订单处理中...
client-111:交易成功,库存余量:8
client-71:交易成功,库存余量:9
client-291:订单处理中...
client-261:订单处理中...
client-281:订单处理中...
client-271:订单处理中...
client-251:订单处理中...
client-241:订单处理中...
client-231:订单处理中...
client-221:订单处理中...
client-211:订单处理中...
client-41:交易成功,库存余量:7
client-101:交易成功,库存余量:6
client-51:交易成功,库存余量:5
client-251:交易成功,库存余量:4
client-291:交易成功,库存余量:3
client-171:交易成功,库存余量:2
client-271:交易成功,库存余量:1
client-01:交易成功,库存余量:0
client-121:交易成功,库存余量:-1
client-201:交易成功,库存余量:-2
client-261:交易成功,库存余量:-3
client-281:交易成功,库存余量:-4
client-151:交易成功,库存余量:-5
client-131:交易成功,库存余量:-6
client-221:交易成功,库存余量:-7
client-241:交易成功,库存余量:-8
client-61:交易成功,库存余量:-9
client-21:交易成功,库存余量:-10
client-161:交易成功,库存余量:-11
client-81:交易成功,库存余量:-12
client-191:交易成功,库存余量:-13
client-141:交易成功,库存余量:-14
client-211:交易成功,库存余量:-15
client-11:交易成功,库存余量:-16
client-31:交易成功,库存余量:-17
client-231:交易成功,库存余量:-18
client-181:交易成功,库存余量:-19
client-91:交易成功,库存余量:-20

java提供给我们一个synchronized关键字,我们理解为同步锁,当操作多个线程共享的数据时,将必须保护的操作放置到synchronized关键字的作用域——同步代码块中,即可保证,在同一时间,只有一个线程,对共享数据进行操作,将SalesThread源代码修改为如下形式:

public class SalesThread implements Runnable {
	private int stock = 10;
	private Object lock = new Object();

    public void run() {
    		while(stock>0){
    			synchronized(lock){
    				if(stock>0){
    					try{
    						Integer processingTime = new Random().nextInt(1000);
    						System.out.println(Thread.currentThread().getName() +":订单处理中...");
    						Thread.sleep(processingTime);
    						System.out.println(Thread.currentThread().getName() +
    								":交易成功,库存余量:" + --stock );
    					}catch(InterruptedException e){
    						e.printStackTrace();
    					}
    			}
    		}
    	}
    }
}

处理结果如下:

client-1:订单处理中...
client-1:交易成功,库存余量:9
client-8:订单处理中...
client-8:交易成功,库存余量:8
client-30:订单处理中...
client-30:交易成功,库存余量:7
client-30:订单处理中...
client-30:交易成功,库存余量:6
client-29:订单处理中...
client-29:交易成功,库存余量:5
client-28:订单处理中...
client-28:交易成功,库存余量:4
client-27:订单处理中...
client-27:交易成功,库存余量:3
client-25:订单处理中...
client-25:交易成功,库存余量:2
client-26:订单处理中...
client-26:交易成功,库存余量:1
client-24:订单处理中...
client-24:交易成功,库存余量:0
时间: 2024-08-06 16:03:03

Java线程安全与同步代码块的相关文章

[java多线程] - 锁机制&amp;同步代码块&amp;信号量

在美眉图片下载demo中,我们可以看到多个线程在公用一些变量,这个时候难免会发生冲突.冲突并不可怕,可怕的是当多线程的情况下,你没法控制冲突.按照我的理解在java中实现同步的方式分为三种,分别是:同步代码块机制,锁机制,信号量机制. 一.同步代码块 在java的多线程并发开发过程中,我们最常用的方式就是使用同步代码关键字(synchronized).这种方式的使用不是特别复杂,需要注意的只是你需要明确到底同步的是那个对象,只有当同步的对象一致的情况下,才能够控制互斥的操作.一般情况下,我们会同

Java的synchronized的同步代码块和同步方法的区别

线程同步问题大都使用synchronized解决,有同步代码块和同步方法的两种方式,主要记一下这两种的区别 测试代码: 1 package com.xujingyang.testThread; 2 3 public class SynObj{ 4 public synchronized void showA(){ 5 System.out.println("showA.."); 6 try { 7 Thread.sleep(3000); 8 } catch (InterruptedEx

java的同步方法和同步代码块,对象锁,类锁区别

/** * @author admin * @date 2018/1/12 9:48 * 作用在同一个实例对象上讨论 * synchronized同步方法的测试 * 两个线程,一个线程调用synchronized修饰方法,另一个线程可以调用非synchronized修饰的方法,互不影响 */ public class SynchronizedTest { public synchronized void methodA() { try { for (int i = 0; i < 5; i++)

阶段1 语言基础+高级_1-3-Java语言高级_05-异常与多线程_第3节 线程同步机制_4_解决线程安全问题_同步代码块

同步代码块 解决了线程安全的问题. 原文地址:https://www.cnblogs.com/wangjunwei/p/11260470.html

彻底理解线程同步与同步代码块synchronized

1 public class Demo { 2 public static synchronized void fun1(){ 3 } 4 public synchronized void fun2(){ 5 } 6 public static void main(String args[]) throws Exception{ 7 synchronized(xxx) { 8 9 } 10 } 11 } 三种同步类型 虽然写法不同,但实际上,只有一种,就是[同步代码块].这是核心核心核心.同步方

java 同步代码块与同步方法

同步代码块 synchronized (obj) { // 代码块 } obj 为同步监视器,以上代码的含义为:线程开始执行同步代码块(中的代码)之前,必须先获得对同步监视器的锁定. 代码块中的代码是执行代码,即是某个方法中的某一部分代码,synchronized(obj){}只能出现在某个方法中.如: public void test() { synchronized (obj) { // 代码块 } } 而不能出现在其他位置,如下则报错: public class Test { public

JAVA之旅(十三)——线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this

JAVA之旅(十三)--线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this 我们继续上个篇幅接着讲线程的知识点 一.线程的安全性 当我们开启四个窗口(线程)把票陆陆续续的卖完了之后,我们要反思一下,这里面有没有安全隐患呢?在实际情况中,这种事情我们是必须要去考虑安全问题的,那我们模拟一下错误 package com.lgl.hellojava; import javax.security.auth.callback.TextInputCallback

java中使用wait就得使用同步锁,而且2个线程必须都使用同步代码块,否则就会异常

标题已经说明,子线程wai()时候默认的锁不是同步代码块的锁,因此wai时候显示的指明锁,现在解释看code: public class Test { // static boolean flag=true; public static void main(String[] args) throws InterruptedException { Zp z=new Zp(); Thread st=new Thread(z); st.start(); for(int x=0;x<100000;x++

java线程同步--同步代码块

package com.LearnJava.Thread; /* 同步代码块 synchronized(同步监视器){ //需要同步的代码 } 同步监视器:俗称 锁,可以是任何实例化的类.但是需要共用同一个实例. */ class WindowSell implements Runnable{ Object obj = new Object(); private int ticket = 100; @Override public void run() { while (true) { sync