实现Demo:
package com.appleyk.dbinit.Ticket;
import java.util.ArrayList;
import java.util.List;
/**
* synchronize对资源加锁,实现同步并发售票
*
* @author Appleyk
* @blob https://blog.csdn.net/appleyk
* @date created on 下午 4:33 2019-7-5
*/
public class SyncSale {
public static void main(String[] args) {
// 假设余票只剩50张
final Integer ticket = 50;
MySyncSale mySyncSale = new MySyncSale(ticket);
// 我们假设有五个窗口同时售票,开启五个线程
List threadList = new ArrayList<>(5);
for (int i = 0; i < 5; i++) {
threadList.add(new Thread(mySyncSale));
}
for (Thread thread : threadList) {
thread.start();
}
}
static class MySyncSale implements Runnable{
Integer ticket ;
public MySyncSale(Integer ticket){
this.ticket = ticket;
}
@Override
public void run() {
while (true){
//对当前对象加锁,保证每次只有一个线程去处理ticket
synchronized (this){
String threadName = Thread.currentThread().getName();
if(--ticket < 0){
System.out.println(threadName+" -- 票已售完");
// 这个时候,不用考虑锁的释放,由JVM自动释放
return;
}else {
// 否则,售票
System.out.println(threadName + " -- 售出1张票,余票:" + ticket);
}
}
// 为了保证肉眼可见,售票的线程休眠100ms
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
实现效果(多次执行,确保票数安全、正确后才贴出代码):
"C:\Program Files\Java\jdk1.8.0_91\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.1.5\lib\idea_rt.jar=56951:C:\Program Files\JetBrains\IntelliJ IDEA 2018.1.5\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_91\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\rt.jar;E:\Spring-boot\db-init\target\test-classes;E:\Spring-boot\db-init\target\classes;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-starter-web\2.1.4.RELEASE\spring-boot-starter-web-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-starter-json\2.1.4.RELEASE\spring-boot-starter-json-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\com\fasterxml\jackson\core\jackson-databind\2.9.8\jackson-databind-2.9.8.jar;D:\Maven3.5\Maven_Jar\com\fasterxml\jackson\core\jackson-annotations\2.9.0\jackson-annotations-2.9.0.jar;D:\Maven3.5\Maven_Jar\com\fasterxml\jackson\core\jackson-core\2.9.8\jackson-core-2.9.8.jar;D:\Maven3.5\Maven_Jar\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.9.8\jackson-datatype-jdk8-2.9.8.jar;D:\Maven3.5\Maven_Jar\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.9.8\jackson-datatype-jsr310-2.9.8.jar;D:\Maven3.5\Maven_Jar\com\fasterxml\jackson\module\jackson-module-parameter-names\2.9.8\jackson-module-parameter-names-2.9.8.jar;D:\Maven3.5\Maven_Jar\org\hibernate\validator\hibernate-validator\6.0.16.Final\hibernate-validator-6.0.16.Final.jar;D:\Maven3.5\Maven_Jar\javax\validation\validation-api\2.0.1.Final\validation-api-2.0.1.Final.jar;D:\Maven3.5\Maven_Jar\org\jboss\logging\jboss-logging\3.3.2.Final\jboss-logging-3.3.2.Final.jar;D:\Maven3.5\Maven_Jar\com\fasterxml\classmate\1.4.0\classmate-1.4.0.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-web\5.1.6.RELEASE\spring-web-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-beans\5.1.6.RELEASE\spring-beans-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-webmvc\5.1.6.RELEASE\spring-webmvc-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-aop\5.1.6.RELEASE\spring-aop-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-context\5.1.6.RELEASE\spring-context-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-expression\5.1.6.RELEASE\spring-expression-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-starter\2.1.4.RELEASE\spring-boot-starter-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot\2.1.4.RELEASE\spring-boot-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-autoconfigure\2.1.4.RELEASE\spring-boot-autoconfigure-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-starter-logging\2.1.4.RELEASE\spring-boot-starter-logging-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\Maven3.5\Maven_Jar\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\Maven3.5\Maven_Jar\org\apache\logging\log4j\log4j-to-slf4j\2.11.2\log4j-to-slf4j-2.11.2.jar;D:\Maven3.5\Maven_Jar\org\apache\logging\log4j\log4j-api\2.11.2\log4j-api-2.11.2.jar;D:\Maven3.5\Maven_Jar\org\slf4j\jul-to-slf4j\1.7.26\jul-to-slf4j-1.7.26.jar;D:\Maven3.5\Maven_Jar\javax\annotation\javax.annotation-api\1.3.2\javax.annotation-api-1.3.2.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-core\5.1.6.RELEASE\spring-core-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-jcl\5.1.6.RELEASE\spring-jcl-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\yaml\snakeyaml\1.23\snakeyaml-1.23.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-starter-tomcat\2.1.4.RELEASE\spring-boot-starter-tomcat-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\apache\tomcat\embed\tomcat-embed-core\9.0.17\tomcat-embed-core-9.0.17.jar;D:\Maven3.5\Maven_Jar\org\apache\tomcat\embed\tomcat-embed-el\9.0.17\tomcat-embed-el-9.0.17.jar;D:\Maven3.5\Maven_Jar\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.17\tomcat-embed-websocket-9.0.17.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-starter-test\2.1.4.RELEASE\spring-boot-starter-test-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-test\2.1.4.RELEASE\spring-boot-test-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-test-autoconfigure\2.1.4.RELEASE\spring-boot-test-autoconfigure-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\com\jayway\jsonpath\json-path\2.4.0\json-path-2.4.0.jar;D:\Maven3.5\Maven_Jar\net\minidev\json-smart\2.3\json-smart-2.3.jar;D:\Maven3.5\Maven_Jar\net\minidev\accessors-smart\1.2\accessors-smart-1.2.jar;D:\Maven3.5\Maven_Jar\org\ow2\asm\asm\5.0.4\asm-5.0.4.jar;D:\Maven3.5\Maven_Jar\org\slf4j\slf4j-api\1.7.26\slf4j-api-1.7.26.jar;D:\Maven3.5\Maven_Jar\junit\junit\4.12\junit-4.12.jar;D:\Maven3.5\Maven_Jar\org\assertj\assertj-core\3.11.1\assertj-core-3.11.1.jar;D:\Maven3.5\Maven_Jar\org\mockito\mockito-core\2.23.4\mockito-core-2.23.4.jar;D:\Maven3.5\Maven_Jar\net\bytebuddy\byte-buddy\1.9.12\byte-buddy-1.9.12.jar;D:\Maven3.5\Maven_Jar\net\bytebuddy\byte-buddy-agent\1.9.12\byte-buddy-agent-1.9.12.jar;D:\Maven3.5\Maven_Jar\org\objenesis\objenesis\2.6\objenesis-2.6.jar;D:\Maven3.5\Maven_Jar\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;D:\Maven3.5\Maven_Jar\org\hamcrest\hamcrest-library\1.3\hamcrest-library-1.3.jar;D:\Maven3.5\Maven_Jar\org\skyscreamer\jsonassert\1.5.0\jsonassert-1.5.0.jar;D:\Maven3.5\Maven_Jar\com\vaadin\external\google\android-json\0.0.20131108.vaadin1\android-json-0.0.20131108.vaadin1.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-test\5.1.6.RELEASE\spring-test-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\xmlunit\xmlunit-core\2.6.2\xmlunit-core-2.6.2.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-starter-jdbc\2.1.4.RELEASE\spring-boot-starter-jdbc-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\com\zaxxer\HikariCP\3.2.0\HikariCP-3.2.0.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-jdbc\5.1.6.RELEASE\spring-jdbc-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-tx\5.1.6.RELEASE\spring-tx-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\mybatis\spring\boot\mybatis-spring-boot-starter\2.0.1\mybatis-spring-boot-starter-2.0.1.jar;D:\Maven3.5\Maven_Jar\org\mybatis\spring\boot\mybatis-spring-boot-autoconfigure\2.0.1\mybatis-spring-boot-autoconfigure-2.0.1.jar;D:\Maven3.5\Maven_Jar\org\mybatis\mybatis\3.5.1\mybatis-3.5.1.jar;D:\Maven3.5\Maven_Jar\org\mybatis\mybatis-spring\2.0.1\mybatis-spring-2.0.1.jar;D:\Maven3.5\Maven_Jar\org\postgresql\postgresql\42.2.5\postgresql-42.2.5.jar" com.appleyk.dbinit.Ticket.SyncSale
Thread-0 -- 售出1张票,余票:49
Thread-1 -- 售出1张票,余票:48
Thread-2 -- 售出1张票,余票:47
Thread-3 -- 售出1张票,余票:46
Thread-4 -- 售出1张票,余票:45
Thread-2 -- 售出1张票,余票:44
Thread-3 -- 售出1张票,余票:43
Thread-0 -- 售出1张票,余票:42
Thread-4 -- 售出1张票,余票:41
Thread-1 -- 售出1张票,余票:40
Thread-0 -- 售出1张票,余票:39
Thread-1 -- 售出1张票,余票:38
Thread-2 -- 售出1张票,余票:37
Thread-4 -- 售出1张票,余票:36
Thread-3 -- 售出1张票,余票:35
Thread-0 -- 售出1张票,余票:34
Thread-1 -- 售出1张票,余票:33
Thread-2 -- 售出1张票,余票:32
Thread-4 -- 售出1张票,余票:31
Thread-3 -- 售出1张票,余票:30
Thread-2 -- 售出1张票,余票:29
Thread-1 -- 售出1张票,余票:28
Thread-4 -- 售出1张票,余票:27
Thread-3 -- 售出1张票,余票:26
Thread-0 -- 售出1张票,余票:25
Thread-0 -- 售出1张票,余票:24
Thread-3 -- 售出1张票,余票:23
Thread-1 -- 售出1张票,余票:22
Thread-2 -- 售出1张票,余票:21
Thread-4 -- 售出1张票,余票:20
Thread-2 -- 售出1张票,余票:19
Thread-3 -- 售出1张票,余票:18
Thread-0 -- 售出1张票,余票:17
Thread-4 -- 售出1张票,余票:16
Thread-1 -- 售出1张票,余票:15
Thread-0 -- 售出1张票,余票:14
Thread-4 -- 售出1张票,余票:13
Thread-3 -- 售出1张票,余票:12
Thread-1 -- 售出1张票,余票:11
Thread-2 -- 售出1张票,余票:10
Thread-3 -- 售出1张票,余票:9
Thread-1 -- 售出1张票,余票:8
Thread-4 -- 售出1张票,余票:7
Thread-0 -- 售出1张票,余票:6
Thread-2 -- 售出1张票,余票:5
Thread-3 -- 售出1张票,余票:4
Thread-0 -- 售出1张票,余票:3
Thread-1 -- 售出1张票,余票:2
Thread-4 -- 售出1张票,余票:1
Thread-2 -- 售出1张票,余票:0
Thread-3 -- 票已售完
Thread-0 -- 票已售完
Thread-1 -- 票已售完
Thread-4 -- 票已售完
Thread-2 -- 票已售完
Process finished with exit code 0
实现Demo:
package com.appleyk.dbinit.Ticket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
/**
* 手动加锁/解锁,实现并发售票
*
* @author Appleyk
* @blob https://blog.csdn.net/appleyk
* @date created on 下午 4:33 2019-7-5
*/
public class LockSale {
public static void main(String[] args) {
// 假设余票只剩50张
Integer ticket = 50;
// 默认非公平锁
ReentrantLock lock = new ReentrantLock();
LockSyncSale mySyncSale = new LockSyncSale(ticket,lock);
// 我们假设有五个窗口同时售票,开启五个线程
List threadList = new ArrayList<>(5);
for (int i = 0; i < 5; i++) {
threadList.add(new Thread(mySyncSale));
}
for (Thread thread : threadList) {
thread.start();
}
}
static class LockSyncSale implements Runnable{
Integer ticket ;
ReentrantLock lock;
public LockSyncSale(Integer ticket,ReentrantLock lock){
this.ticket = ticket;
this.lock = lock;
}
@Override
public void run() {
while (true){
try{
// 加锁,在没有主动释放锁时,其他进程禁止对ticket进行操作
lock.lock();
String threadName = Thread.currentThread().getName();
if(ticket == 0){
System.out.println(threadName+" -- 票已售完");
// 这个时候,不用考虑锁的释放,由JVM自动释放
return;
}else {
ticket = ticket - 1;
// 否则,售票
System.out.println(threadName + " -- 售出1张票,余票:" + ticket);
}
// 为了保证肉眼可见,售票的线程休眠100ms
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}finally {
// 不管操作成功与否,最后都要把锁释放了,注意一定要手动是否,否则会造成线程阻塞
lock.unlock();
}
}
}
}
}
实现效果(多次执行,确保票数安全、正确后才贴出代码):
"C:\Program Files\Java\jdk1.8.0_91\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.1.5\lib\idea_rt.jar=54149:C:\Program Files\JetBrains\IntelliJ IDEA 2018.1.5\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_91\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\rt.jar;E:\Spring-boot\db-init\target\test-classes;E:\Spring-boot\db-init\target\classes;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-starter-web\2.1.4.RELEASE\spring-boot-starter-web-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-starter-json\2.1.4.RELEASE\spring-boot-starter-json-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\com\fasterxml\jackson\core\jackson-databind\2.9.8\jackson-databind-2.9.8.jar;D:\Maven3.5\Maven_Jar\com\fasterxml\jackson\core\jackson-annotations\2.9.0\jackson-annotations-2.9.0.jar;D:\Maven3.5\Maven_Jar\com\fasterxml\jackson\core\jackson-core\2.9.8\jackson-core-2.9.8.jar;D:\Maven3.5\Maven_Jar\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.9.8\jackson-datatype-jdk8-2.9.8.jar;D:\Maven3.5\Maven_Jar\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.9.8\jackson-datatype-jsr310-2.9.8.jar;D:\Maven3.5\Maven_Jar\com\fasterxml\jackson\module\jackson-module-parameter-names\2.9.8\jackson-module-parameter-names-2.9.8.jar;D:\Maven3.5\Maven_Jar\org\hibernate\validator\hibernate-validator\6.0.16.Final\hibernate-validator-6.0.16.Final.jar;D:\Maven3.5\Maven_Jar\javax\validation\validation-api\2.0.1.Final\validation-api-2.0.1.Final.jar;D:\Maven3.5\Maven_Jar\org\jboss\logging\jboss-logging\3.3.2.Final\jboss-logging-3.3.2.Final.jar;D:\Maven3.5\Maven_Jar\com\fasterxml\classmate\1.4.0\classmate-1.4.0.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-web\5.1.6.RELEASE\spring-web-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-beans\5.1.6.RELEASE\spring-beans-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-webmvc\5.1.6.RELEASE\spring-webmvc-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-aop\5.1.6.RELEASE\spring-aop-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-context\5.1.6.RELEASE\spring-context-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-expression\5.1.6.RELEASE\spring-expression-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-starter\2.1.4.RELEASE\spring-boot-starter-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot\2.1.4.RELEASE\spring-boot-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-autoconfigure\2.1.4.RELEASE\spring-boot-autoconfigure-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-starter-logging\2.1.4.RELEASE\spring-boot-starter-logging-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\Maven3.5\Maven_Jar\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\Maven3.5\Maven_Jar\org\apache\logging\log4j\log4j-to-slf4j\2.11.2\log4j-to-slf4j-2.11.2.jar;D:\Maven3.5\Maven_Jar\org\apache\logging\log4j\log4j-api\2.11.2\log4j-api-2.11.2.jar;D:\Maven3.5\Maven_Jar\org\slf4j\jul-to-slf4j\1.7.26\jul-to-slf4j-1.7.26.jar;D:\Maven3.5\Maven_Jar\javax\annotation\javax.annotation-api\1.3.2\javax.annotation-api-1.3.2.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-core\5.1.6.RELEASE\spring-core-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-jcl\5.1.6.RELEASE\spring-jcl-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\yaml\snakeyaml\1.23\snakeyaml-1.23.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-starter-tomcat\2.1.4.RELEASE\spring-boot-starter-tomcat-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\apache\tomcat\embed\tomcat-embed-core\9.0.17\tomcat-embed-core-9.0.17.jar;D:\Maven3.5\Maven_Jar\org\apache\tomcat\embed\tomcat-embed-el\9.0.17\tomcat-embed-el-9.0.17.jar;D:\Maven3.5\Maven_Jar\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.17\tomcat-embed-websocket-9.0.17.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-starter-test\2.1.4.RELEASE\spring-boot-starter-test-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-test\2.1.4.RELEASE\spring-boot-test-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-test-autoconfigure\2.1.4.RELEASE\spring-boot-test-autoconfigure-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\com\jayway\jsonpath\json-path\2.4.0\json-path-2.4.0.jar;D:\Maven3.5\Maven_Jar\net\minidev\json-smart\2.3\json-smart-2.3.jar;D:\Maven3.5\Maven_Jar\net\minidev\accessors-smart\1.2\accessors-smart-1.2.jar;D:\Maven3.5\Maven_Jar\org\ow2\asm\asm\5.0.4\asm-5.0.4.jar;D:\Maven3.5\Maven_Jar\org\slf4j\slf4j-api\1.7.26\slf4j-api-1.7.26.jar;D:\Maven3.5\Maven_Jar\junit\junit\4.12\junit-4.12.jar;D:\Maven3.5\Maven_Jar\org\assertj\assertj-core\3.11.1\assertj-core-3.11.1.jar;D:\Maven3.5\Maven_Jar\org\mockito\mockito-core\2.23.4\mockito-core-2.23.4.jar;D:\Maven3.5\Maven_Jar\net\bytebuddy\byte-buddy\1.9.12\byte-buddy-1.9.12.jar;D:\Maven3.5\Maven_Jar\net\bytebuddy\byte-buddy-agent\1.9.12\byte-buddy-agent-1.9.12.jar;D:\Maven3.5\Maven_Jar\org\objenesis\objenesis\2.6\objenesis-2.6.jar;D:\Maven3.5\Maven_Jar\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;D:\Maven3.5\Maven_Jar\org\hamcrest\hamcrest-library\1.3\hamcrest-library-1.3.jar;D:\Maven3.5\Maven_Jar\org\skyscreamer\jsonassert\1.5.0\jsonassert-1.5.0.jar;D:\Maven3.5\Maven_Jar\com\vaadin\external\google\android-json\0.0.20131108.vaadin1\android-json-0.0.20131108.vaadin1.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-test\5.1.6.RELEASE\spring-test-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\xmlunit\xmlunit-core\2.6.2\xmlunit-core-2.6.2.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-starter-jdbc\2.1.4.RELEASE\spring-boot-starter-jdbc-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\com\zaxxer\HikariCP\3.2.0\HikariCP-3.2.0.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-jdbc\5.1.6.RELEASE\spring-jdbc-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-tx\5.1.6.RELEASE\spring-tx-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\mybatis\spring\boot\mybatis-spring-boot-starter\2.0.1\mybatis-spring-boot-starter-2.0.1.jar;D:\Maven3.5\Maven_Jar\org\mybatis\spring\boot\mybatis-spring-boot-autoconfigure\2.0.1\mybatis-spring-boot-autoconfigure-2.0.1.jar;D:\Maven3.5\Maven_Jar\org\mybatis\mybatis\3.5.1\mybatis-3.5.1.jar;D:\Maven3.5\Maven_Jar\org\mybatis\mybatis-spring\2.0.1\mybatis-spring-2.0.1.jar;D:\Maven3.5\Maven_Jar\org\postgresql\postgresql\42.2.5\postgresql-42.2.5.jar" com.appleyk.dbinit.Ticket.LockSale
Thread-0 -- 售出1张票,余票:49
Thread-0 -- 售出1张票,余票:48
Thread-0 -- 售出1张票,余票:47
Thread-0 -- 售出1张票,余票:46
Thread-3 -- 售出1张票,余票:45
Thread-3 -- 售出1张票,余票:44
Thread-3 -- 售出1张票,余票:43
Thread-3 -- 售出1张票,余票:42
Thread-3 -- 售出1张票,余票:41
Thread-3 -- 售出1张票,余票:40
Thread-3 -- 售出1张票,余票:39
Thread-3 -- 售出1张票,余票:38
Thread-3 -- 售出1张票,余票:37
Thread-3 -- 售出1张票,余票:36
Thread-3 -- 售出1张票,余票:35
Thread-3 -- 售出1张票,余票:34
Thread-3 -- 售出1张票,余票:33
Thread-3 -- 售出1张票,余票:32
Thread-3 -- 售出1张票,余票:31
Thread-3 -- 售出1张票,余票:30
Thread-3 -- 售出1张票,余票:29
Thread-3 -- 售出1张票,余票:28
Thread-3 -- 售出1张票,余票:27
Thread-3 -- 售出1张票,余票:26
Thread-3 -- 售出1张票,余票:25
Thread-3 -- 售出1张票,余票:24
Thread-3 -- 售出1张票,余票:23
Thread-3 -- 售出1张票,余票:22
Thread-3 -- 售出1张票,余票:21
Thread-3 -- 售出1张票,余票:20
Thread-4 -- 售出1张票,余票:19
Thread-4 -- 售出1张票,余票:18
Thread-4 -- 售出1张票,余票:17
Thread-4 -- 售出1张票,余票:16
Thread-4 -- 售出1张票,余票:15
Thread-4 -- 售出1张票,余票:14
Thread-4 -- 售出1张票,余票:13
Thread-4 -- 售出1张票,余票:12
Thread-4 -- 售出1张票,余票:11
Thread-4 -- 售出1张票,余票:10
Thread-4 -- 售出1张票,余票:9
Thread-4 -- 售出1张票,余票:8
Thread-4 -- 售出1张票,余票:7
Thread-4 -- 售出1张票,余票:6
Thread-4 -- 售出1张票,余票:5
Thread-4 -- 售出1张票,余票:4
Thread-4 -- 售出1张票,余票:3
Thread-4 -- 售出1张票,余票:2
Thread-4 -- 售出1张票,余票:1
Thread-4 -- 售出1张票,余票:0
Thread-4 -- 票已售完
Thread-1 -- 票已售完
Thread-2 -- 票已售完
Thread-0 -- 票已售完
Thread-3 -- 票已售完
Process finished with exit code 0
实现Demo:
package com.appleyk.dbinit.Ticket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 原子操作,实现无锁并发售票
*
* @author Appleyk
* @blob https://blog.csdn.net/appleyk
* @date created on 下午 4:33 2019-7-5
*/
public class AtomicSale {
public static void main(String[] args) {
// 假设余票只剩50张
AtomicInteger ticket = new AtomicInteger(50);
MyAtomicSale mySyncSale = new MyAtomicSale(ticket);
// 我们假设有五个窗口同时售票,开启五个线程
List threadList = new ArrayList<>(5);
for (int i = 0; i < 5; i++) {
threadList.add(new Thread(mySyncSale));
}
for (Thread thread : threadList) {
thread.start();
}
}
static class MyAtomicSale implements Runnable {
AtomicInteger ticket;
public MyAtomicSale(AtomicInteger ticket) {
this.ticket = ticket;
}
@Override
public void run() {
int count ;
while (true) {
String threadName = Thread.currentThread().getName();
// 实现CAS操作,每次ticket-1
if ((count = ticket.decrementAndGet()) < 0) {
System.out.println(threadName + " -- 票已售完");
return;
} else {
// 否则,售票
System.out.println(threadName + " -- 售出1张票,余票:" + count);
}
// 为了保证肉眼可见,售票的线程休眠100ms
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
实现效果(多次执行,确保票数安全、正确后才贴出代码):
"C:\Program Files\Java\jdk1.8.0_91\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.1.5\lib\idea_rt.jar=55014:C:\Program Files\JetBrains\IntelliJ IDEA 2018.1.5\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_91\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_91\jre\lib\rt.jar;E:\Spring-boot\db-init\target\test-classes;E:\Spring-boot\db-init\target\classes;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-starter-web\2.1.4.RELEASE\spring-boot-starter-web-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-starter-json\2.1.4.RELEASE\spring-boot-starter-json-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\com\fasterxml\jackson\core\jackson-databind\2.9.8\jackson-databind-2.9.8.jar;D:\Maven3.5\Maven_Jar\com\fasterxml\jackson\core\jackson-annotations\2.9.0\jackson-annotations-2.9.0.jar;D:\Maven3.5\Maven_Jar\com\fasterxml\jackson\core\jackson-core\2.9.8\jackson-core-2.9.8.jar;D:\Maven3.5\Maven_Jar\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.9.8\jackson-datatype-jdk8-2.9.8.jar;D:\Maven3.5\Maven_Jar\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.9.8\jackson-datatype-jsr310-2.9.8.jar;D:\Maven3.5\Maven_Jar\com\fasterxml\jackson\module\jackson-module-parameter-names\2.9.8\jackson-module-parameter-names-2.9.8.jar;D:\Maven3.5\Maven_Jar\org\hibernate\validator\hibernate-validator\6.0.16.Final\hibernate-validator-6.0.16.Final.jar;D:\Maven3.5\Maven_Jar\javax\validation\validation-api\2.0.1.Final\validation-api-2.0.1.Final.jar;D:\Maven3.5\Maven_Jar\org\jboss\logging\jboss-logging\3.3.2.Final\jboss-logging-3.3.2.Final.jar;D:\Maven3.5\Maven_Jar\com\fasterxml\classmate\1.4.0\classmate-1.4.0.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-web\5.1.6.RELEASE\spring-web-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-beans\5.1.6.RELEASE\spring-beans-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-webmvc\5.1.6.RELEASE\spring-webmvc-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-aop\5.1.6.RELEASE\spring-aop-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-context\5.1.6.RELEASE\spring-context-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-expression\5.1.6.RELEASE\spring-expression-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-starter\2.1.4.RELEASE\spring-boot-starter-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot\2.1.4.RELEASE\spring-boot-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-autoconfigure\2.1.4.RELEASE\spring-boot-autoconfigure-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-starter-logging\2.1.4.RELEASE\spring-boot-starter-logging-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\Maven3.5\Maven_Jar\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\Maven3.5\Maven_Jar\org\apache\logging\log4j\log4j-to-slf4j\2.11.2\log4j-to-slf4j-2.11.2.jar;D:\Maven3.5\Maven_Jar\org\apache\logging\log4j\log4j-api\2.11.2\log4j-api-2.11.2.jar;D:\Maven3.5\Maven_Jar\org\slf4j\jul-to-slf4j\1.7.26\jul-to-slf4j-1.7.26.jar;D:\Maven3.5\Maven_Jar\javax\annotation\javax.annotation-api\1.3.2\javax.annotation-api-1.3.2.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-core\5.1.6.RELEASE\spring-core-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-jcl\5.1.6.RELEASE\spring-jcl-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\yaml\snakeyaml\1.23\snakeyaml-1.23.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-starter-tomcat\2.1.4.RELEASE\spring-boot-starter-tomcat-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\apache\tomcat\embed\tomcat-embed-core\9.0.17\tomcat-embed-core-9.0.17.jar;D:\Maven3.5\Maven_Jar\org\apache\tomcat\embed\tomcat-embed-el\9.0.17\tomcat-embed-el-9.0.17.jar;D:\Maven3.5\Maven_Jar\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.17\tomcat-embed-websocket-9.0.17.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-starter-test\2.1.4.RELEASE\spring-boot-starter-test-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-test\2.1.4.RELEASE\spring-boot-test-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-test-autoconfigure\2.1.4.RELEASE\spring-boot-test-autoconfigure-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\com\jayway\jsonpath\json-path\2.4.0\json-path-2.4.0.jar;D:\Maven3.5\Maven_Jar\net\minidev\json-smart\2.3\json-smart-2.3.jar;D:\Maven3.5\Maven_Jar\net\minidev\accessors-smart\1.2\accessors-smart-1.2.jar;D:\Maven3.5\Maven_Jar\org\ow2\asm\asm\5.0.4\asm-5.0.4.jar;D:\Maven3.5\Maven_Jar\org\slf4j\slf4j-api\1.7.26\slf4j-api-1.7.26.jar;D:\Maven3.5\Maven_Jar\junit\junit\4.12\junit-4.12.jar;D:\Maven3.5\Maven_Jar\org\assertj\assertj-core\3.11.1\assertj-core-3.11.1.jar;D:\Maven3.5\Maven_Jar\org\mockito\mockito-core\2.23.4\mockito-core-2.23.4.jar;D:\Maven3.5\Maven_Jar\net\bytebuddy\byte-buddy\1.9.12\byte-buddy-1.9.12.jar;D:\Maven3.5\Maven_Jar\net\bytebuddy\byte-buddy-agent\1.9.12\byte-buddy-agent-1.9.12.jar;D:\Maven3.5\Maven_Jar\org\objenesis\objenesis\2.6\objenesis-2.6.jar;D:\Maven3.5\Maven_Jar\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;D:\Maven3.5\Maven_Jar\org\hamcrest\hamcrest-library\1.3\hamcrest-library-1.3.jar;D:\Maven3.5\Maven_Jar\org\skyscreamer\jsonassert\1.5.0\jsonassert-1.5.0.jar;D:\Maven3.5\Maven_Jar\com\vaadin\external\google\android-json\0.0.20131108.vaadin1\android-json-0.0.20131108.vaadin1.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-test\5.1.6.RELEASE\spring-test-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\xmlunit\xmlunit-core\2.6.2\xmlunit-core-2.6.2.jar;D:\Maven3.5\Maven_Jar\org\springframework\boot\spring-boot-starter-jdbc\2.1.4.RELEASE\spring-boot-starter-jdbc-2.1.4.RELEASE.jar;D:\Maven3.5\Maven_Jar\com\zaxxer\HikariCP\3.2.0\HikariCP-3.2.0.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-jdbc\5.1.6.RELEASE\spring-jdbc-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\springframework\spring-tx\5.1.6.RELEASE\spring-tx-5.1.6.RELEASE.jar;D:\Maven3.5\Maven_Jar\org\mybatis\spring\boot\mybatis-spring-boot-starter\2.0.1\mybatis-spring-boot-starter-2.0.1.jar;D:\Maven3.5\Maven_Jar\org\mybatis\spring\boot\mybatis-spring-boot-autoconfigure\2.0.1\mybatis-spring-boot-autoconfigure-2.0.1.jar;D:\Maven3.5\Maven_Jar\org\mybatis\mybatis\3.5.1\mybatis-3.5.1.jar;D:\Maven3.5\Maven_Jar\org\mybatis\mybatis-spring\2.0.1\mybatis-spring-2.0.1.jar;D:\Maven3.5\Maven_Jar\org\postgresql\postgresql\42.2.5\postgresql-42.2.5.jar" com.appleyk.dbinit.Ticket.AtomicSale
Thread-0 -- 售出1张票,余票:49
Thread-1 -- 售出1张票,余票:48
Thread-2 -- 售出1张票,余票:47
Thread-4 -- 售出1张票,余票:46
Thread-3 -- 售出1张票,余票:45
Thread-2 -- 售出1张票,余票:44
Thread-0 -- 售出1张票,余票:42
Thread-4 -- 售出1张票,余票:41
Thread-1 -- 售出1张票,余票:43
Thread-3 -- 售出1张票,余票:40
Thread-1 -- 售出1张票,余票:37
Thread-3 -- 售出1张票,余票:35
Thread-0 -- 售出1张票,余票:36
Thread-2 -- 售出1张票,余票:39
Thread-4 -- 售出1张票,余票:38
Thread-0 -- 售出1张票,余票:34
Thread-2 -- 售出1张票,余票:30
Thread-3 -- 售出1张票,余票:32
Thread-4 -- 售出1张票,余票:33
Thread-1 -- 售出1张票,余票:31
Thread-1 -- 售出1张票,余票:29
Thread-3 -- 售出1张票,余票:28
Thread-2 -- 售出1张票,余票:27
Thread-0 -- 售出1张票,余票:26
Thread-4 -- 售出1张票,余票:25
Thread-1 -- 售出1张票,余票:24
Thread-2 -- 售出1张票,余票:23
Thread-3 -- 售出1张票,余票:22
Thread-0 -- 售出1张票,余票:21
Thread-4 -- 售出1张票,余票:20
Thread-1 -- 售出1张票,余票:19
Thread-2 -- 售出1张票,余票:18
Thread-3 -- 售出1张票,余票:17
Thread-0 -- 售出1张票,余票:16
Thread-4 -- 售出1张票,余票:15
Thread-1 -- 售出1张票,余票:14
Thread-2 -- 售出1张票,余票:12
Thread-3 -- 售出1张票,余票:13
Thread-0 -- 售出1张票,余票:11
Thread-4 -- 售出1张票,余票:10
Thread-1 -- 售出1张票,余票:9
Thread-3 -- 售出1张票,余票:8
Thread-2 -- 售出1张票,余票:7
Thread-0 -- 售出1张票,余票:6
Thread-4 -- 售出1张票,余票:5
Thread-1 -- 售出1张票,余票:4
Thread-3 -- 售出1张票,余票:3
Thread-2 -- 售出1张票,余票:2
Thread-0 -- 售出1张票,余票:1
Thread-4 -- 售出1张票,余票:0
Thread-1 -- 票已售完
Thread-3 -- 票已售完
Thread-2 -- 票已售完
Thread-0 -- 票已售完
Thread-4 -- 票已售完
Process finished with exit code 0
附加:这种并发操作ticket是无锁模式的,因此性能上要比有锁的要快!