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

一、synchronize(同步锁)

实现Demo:

package com.appleyk.dbinit.Ticket;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>synchronize对资源加锁,实现同步并发售票</p>
 *
 * @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<Thread> 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;

/**
 * <p>手动加锁/解锁,实现并发售票</p>
 *
 * @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<Thread> 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;

/**
 * <p>原子操作,实现无锁并发售票</p>
 *
 * @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<Thread> 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是无锁模式的,因此性能上要比有锁的要快!

发布了208 篇原创文章 · 获赞 645 · 访问量 212万+

猜你喜欢

转载自blog.csdn.net/Appleyk/article/details/94740407