Java -- 浅谈并发下“售票”的三种实现方式

一、synchronize(同步锁)

 

实现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

 

二、ReentrantLock(可重入锁)

 

实现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

 

 

三、AtomicInteger(原子操作,线程安全,CAS锁)

 

实现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是无锁模式的,因此性能上要比有锁的要快!

你可能感兴趣的:(Java锁,Java并发编程)