使用java多线程模拟一个售票系统

简介: 1.基于继承Thread实现代码实现:


1.基于继承Thread实现


代码实现:


/**
 * 多线程模拟售票,基于Thread
 */
public class TicketSalesByThread {
    public static void main(String[] args) {
        SellTicket sellTicket = new SellTicket();
        SellTicket sellTicket1 = new SellTicket();
        SellTicket sellTicket2 = new SellTicket();
        sellTicket.start();
        sellTicket1.start();
        sellTicket2.start();
    }
}
class SellTicket extends Thread {
    // 余票
    private static int ticketNum = 100;
    @Override
    public void run() {
        while (true) {
            if (ticketNum <= 0) {
                System.out.println("没有余票!");
                break;
            }
            // 休眠卖票
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("窗口" + Thread.currentThread().getName() +
                    "售出一张票。" + "剩余票数:" + (--ticketNum));
        }
    }
}


结果分析:


窗口Thread-1售出一张票。剩余票数:97
窗口Thread-0售出一张票。剩余票数:98
窗口Thread-2售出一张票。剩余票数:99
窗口Thread-0售出一张票。剩余票数:96
窗口Thread-1售出一张票。剩余票数:96
窗口Thread-2售出一张票。剩余票数:95
窗口Thread-0售出一张票。剩余票数:94
窗口Thread-1售出一张票。剩余票数:93
窗口Thread-2售出一张票。剩余票数:92
窗口Thread-0售出一张票。剩余票数:91
窗口Thread-1售出一张票。剩余票数:90
窗口Thread-2售出一张票。剩余票数:89
窗口Thread-0售出一张票。剩余票数:88
窗口Thread-1售出一张票。剩余票数:87
窗口Thread-2售出一张票。剩余票数:86
窗口Thread-0售出一张票。剩余票数:85
窗口Thread-1售出一张票。剩余票数:84
窗口Thread-2售出一张票。剩余票数:83
窗口Thread-0售出一张票。剩余票数:82
窗口Thread-1售出一张票。剩余票数:81
窗口Thread-2售出一张票。剩余票数:80
窗口Thread-0售出一张票。剩余票数:79
窗口Thread-1售出一张票。剩余票数:78
窗口Thread-2售出一张票。剩余票数:77
窗口Thread-0售出一张票。剩余票数:76
窗口Thread-1售出一张票。剩余票数:75
窗口Thread-2售出一张票。剩余票数:74
窗口Thread-0售出一张票。剩余票数:73
窗口Thread-1售出一张票。剩余票数:72
窗口Thread-2售出一张票。剩余票数:71
窗口Thread-0售出一张票。剩余票数:70
窗口Thread-1售出一张票。剩余票数:69
窗口Thread-2售出一张票。剩余票数:68
窗口Thread-0售出一张票。剩余票数:67
窗口Thread-1售出一张票。剩余票数:66
窗口Thread-2售出一张票。剩余票数:65
窗口Thread-0售出一张票。剩余票数:64
窗口Thread-1售出一张票。剩余票数:63
窗口Thread-2售出一张票。剩余票数:62
窗口Thread-0售出一张票。剩余票数:61
窗口Thread-1售出一张票。剩余票数:60
窗口Thread-2售出一张票。剩余票数:59
窗口Thread-0售出一张票。剩余票数:58
窗口Thread-1售出一张票。剩余票数:57
窗口Thread-2售出一张票。剩余票数:56
窗口Thread-0售出一张票。剩余票数:55
窗口Thread-1售出一张票。剩余票数:54
窗口Thread-2售出一张票。剩余票数:53
窗口Thread-0售出一张票。剩余票数:52
窗口Thread-1售出一张票。剩余票数:51
窗口Thread-2售出一张票。剩余票数:50
窗口Thread-0售出一张票。剩余票数:49
窗口Thread-1售出一张票。剩余票数:48
窗口Thread-2售出一张票。剩余票数:47
窗口Thread-0售出一张票。剩余票数:46
窗口Thread-1售出一张票。剩余票数:45
窗口Thread-2售出一张票。剩余票数:44
窗口Thread-0售出一张票。剩余票数:43
窗口Thread-1售出一张票。剩余票数:42
窗口Thread-2售出一张票。剩余票数:41
窗口Thread-0售出一张票。剩余票数:40
窗口Thread-1售出一张票。剩余票数:39
窗口Thread-2售出一张票。剩余票数:38
窗口Thread-0售出一张票。剩余票数:37
窗口Thread-1售出一张票。剩余票数:36
窗口Thread-2售出一张票。剩余票数:35
窗口Thread-0售出一张票。剩余票数:34
窗口Thread-1售出一张票。剩余票数:33
窗口Thread-2售出一张票。剩余票数:32
窗口Thread-0售出一张票。剩余票数:31
窗口Thread-1售出一张票。剩余票数:30
窗口Thread-2售出一张票。剩余票数:29
窗口Thread-0售出一张票。剩余票数:28
窗口Thread-1售出一张票。剩余票数:27
窗口Thread-2售出一张票。剩余票数:26
窗口Thread-0售出一张票。剩余票数:25
窗口Thread-1售出一张票。剩余票数:24
窗口Thread-2售出一张票。剩余票数:23
窗口Thread-0售出一张票。剩余票数:22
窗口Thread-1售出一张票。剩余票数:21
窗口Thread-2售出一张票。剩余票数:20
窗口Thread-0售出一张票。剩余票数:19
窗口Thread-1售出一张票。剩余票数:18
窗口Thread-2售出一张票。剩余票数:17
窗口Thread-0售出一张票。剩余票数:16
窗口Thread-1售出一张票。剩余票数:15
窗口Thread-2售出一张票。剩余票数:14
窗口Thread-0售出一张票。剩余票数:13
窗口Thread-1售出一张票。剩余票数:12
窗口Thread-2售出一张票。剩余票数:11
窗口Thread-0售出一张票。剩余票数:10
窗口Thread-1售出一张票。剩余票数:9
窗口Thread-2售出一张票。剩余票数:8
窗口Thread-0售出一张票。剩余票数:7
窗口Thread-1售出一张票。剩余票数:6
窗口Thread-2售出一张票。剩余票数:5
窗口Thread-0售出一张票。剩余票数:4
窗口Thread-1售出一张票。剩余票数:3
窗口Thread-2售出一张票。剩余票数:2
窗口Thread-0售出一张票。剩余票数:1
窗口Thread-1售出一张票。剩余票数:0
没有余票!
窗口Thread-2售出一张票。剩余票数:-1
没有余票!
窗口Thread-0售出一张票。剩余票数:-2
没有余票!


可以看到,基于Thread的实现,出现了明显的超卖现象!😶‍🌫️

那么,为什么会发生这种情况呢?

原因分析:

当一个窗口还未执行--ticketNum操作时,另一个窗口已经进行售票状态,跳过了while循环的限制


2.基于实现Runnable接口实现


代码实现:


/**
 * 多线程模拟售票,基于实现Runnable接口
 */
public class TicketSalesByRunnable {
    public static void main(String[] args) {
        SellTicket02 sellTicket02 = new SellTicket02();
        new Thread(sellTicket02).start();
        new Thread(sellTicket02).start();
        new Thread(sellTicket02).start();
    }
}
class SellTicket02 implements Runnable {
    private int ticketNum = 100;
    @Override
    public void run() {
        while (true) {
            if (ticketNum <= 0) {
                System.out.println("没有余票!");
                break;
            }
            // 休眠卖票
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("窗口" + Thread.currentThread().getName() +
                    "售出一张票。" + "剩余票数:" + (--ticketNum));
        }
    }
}


结果分析:


窗口Thread-0售出一张票。剩余票数:99
窗口Thread-2售出一张票。剩余票数:98
窗口Thread-1售出一张票。剩余票数:98
窗口Thread-0售出一张票。剩余票数:97
窗口Thread-2售出一张票。剩余票数:96
窗口Thread-1售出一张票。剩余票数:95
窗口Thread-0售出一张票。剩余票数:94
窗口Thread-2售出一张票。剩余票数:94
窗口Thread-1售出一张票。剩余票数:93
窗口Thread-2售出一张票。剩余票数:92
窗口Thread-0售出一张票。剩余票数:91
窗口Thread-1售出一张票。剩余票数:90
窗口Thread-2售出一张票。剩余票数:89
窗口Thread-0售出一张票。剩余票数:88
窗口Thread-1售出一张票。剩余票数:87
窗口Thread-0售出一张票。剩余票数:86
窗口Thread-2售出一张票。剩余票数:85
窗口Thread-1售出一张票。剩余票数:84
窗口Thread-2售出一张票。剩余票数:83
窗口Thread-0售出一张票。剩余票数:83
窗口Thread-1售出一张票。剩余票数:82
窗口Thread-2售出一张票。剩余票数:80
窗口Thread-0售出一张票。剩余票数:81
窗口Thread-1售出一张票。剩余票数:79
窗口Thread-2售出一张票。剩余票数:77
窗口Thread-0售出一张票。剩余票数:78
窗口Thread-1售出一张票。剩余票数:76
窗口Thread-2售出一张票。剩余票数:75
窗口Thread-0售出一张票。剩余票数:74
窗口Thread-1售出一张票。剩余票数:73
窗口Thread-2售出一张票。剩余票数:72
窗口Thread-0售出一张票。剩余票数:71
窗口Thread-1售出一张票。剩余票数:70
窗口Thread-2售出一张票。剩余票数:69
窗口Thread-0售出一张票。剩余票数:68
窗口Thread-1售出一张票。剩余票数:67
窗口Thread-2售出一张票。剩余票数:66
窗口Thread-0售出一张票。剩余票数:65
窗口Thread-1售出一张票。剩余票数:64
窗口Thread-2售出一张票。剩余票数:63
窗口Thread-0售出一张票。剩余票数:62
窗口Thread-1售出一张票。剩余票数:61
窗口Thread-2售出一张票。剩余票数:60
窗口Thread-0售出一张票。剩余票数:59
窗口Thread-1售出一张票。剩余票数:58
窗口Thread-2售出一张票。剩余票数:57
窗口Thread-0售出一张票。剩余票数:56
窗口Thread-1售出一张票。剩余票数:55
窗口Thread-2售出一张票。剩余票数:54
窗口Thread-0售出一张票。剩余票数:53
窗口Thread-1售出一张票。剩余票数:52
窗口Thread-2售出一张票。剩余票数:51
窗口Thread-0售出一张票。剩余票数:50
窗口Thread-1售出一张票。剩余票数:49
窗口Thread-2售出一张票。剩余票数:48
窗口Thread-0售出一张票。剩余票数:47
窗口Thread-1售出一张票。剩余票数:46
窗口Thread-2售出一张票。剩余票数:45
窗口Thread-0售出一张票。剩余票数:44
窗口Thread-1售出一张票。剩余票数:43
窗口Thread-2售出一张票。剩余票数:42
窗口Thread-0售出一张票。剩余票数:41
窗口Thread-1售出一张票。剩余票数:40
窗口Thread-2售出一张票。剩余票数:39
窗口Thread-0售出一张票。剩余票数:38
窗口Thread-1售出一张票。剩余票数:37
窗口Thread-2售出一张票。剩余票数:36
窗口Thread-0售出一张票。剩余票数:35
窗口Thread-1售出一张票。剩余票数:34
窗口Thread-2售出一张票。剩余票数:33
窗口Thread-0售出一张票。剩余票数:32
窗口Thread-1售出一张票。剩余票数:31
窗口Thread-2售出一张票。剩余票数:30
窗口Thread-0售出一张票。剩余票数:29
窗口Thread-1售出一张票。剩余票数:28
窗口Thread-2售出一张票。剩余票数:27
窗口Thread-0售出一张票。剩余票数:26
窗口Thread-1售出一张票。剩余票数:25
窗口Thread-2售出一张票。剩余票数:24
窗口Thread-0售出一张票。剩余票数:23
窗口Thread-1售出一张票。剩余票数:22
窗口Thread-2售出一张票。剩余票数:21
窗口Thread-0售出一张票。剩余票数:20
窗口Thread-1售出一张票。剩余票数:19
窗口Thread-2售出一张票。剩余票数:18
窗口Thread-0售出一张票。剩余票数:17
窗口Thread-1售出一张票。剩余票数:16
窗口Thread-2售出一张票。剩余票数:15
窗口Thread-0售出一张票。剩余票数:14
窗口Thread-1售出一张票。剩余票数:13
窗口Thread-2售出一张票。剩余票数:12
窗口Thread-0售出一张票。剩余票数:11
窗口Thread-1售出一张票。剩余票数:10
窗口Thread-2售出一张票。剩余票数:9
窗口Thread-0售出一张票。剩余票数:8
窗口Thread-1售出一张票。剩余票数:7
窗口Thread-2售出一张票。剩余票数:6
窗口Thread-0售出一张票。剩余票数:5
窗口Thread-1售出一张票。剩余票数:4
窗口Thread-2售出一张票。剩余票数:3
窗口Thread-0售出一张票。剩余票数:2
窗口Thread-1售出一张票。剩余票数:1
窗口Thread-2售出一张票。剩余票数:0
没有余票!
窗口Thread-0售出一张票。剩余票数:-1
没有余票!
窗口Thread-1售出一张票。剩余票数:-2
没有余票!


仍然会有超卖现象发生!


3.通知线程退出


有时候,我们需要不同的线程可以相互控制对方的运行

可以采用通知线程中止来解决此类问题,比如我们简单实现一个DEMO,实现主线程通知中止其他线程的效果:


/**
 * 通知线程中止
 */
public class ThreadExit {
    public static void main(String[] args) throws InterruptedException {
        TTT ttt = new TTT();
        ttt.start();
        Thread.sleep(5000);
        // 主线程通知其他线程退出
        ttt.setLoop(false);
    }
}
class TTT extends Thread {
    // 控制变量
    private boolean loop = true;
    @Override
    public void run() {
        while (loop) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("TTT线程正在运行...");
        }
    }
    public void setLoop(boolean loop) {
        this.loop = loop;
    }
}


TTT线程会运行5秒,随后由主线程通知退出🤖


4.解决超卖问题,线程同步机制


在多线程编程中,一些敏感数据不允许被多个线程同时访问,此时就可以使用同步访问技术,保证数据在同一时刻只能有一个线程访问,以保证数据的完整性


synchronized线程同步:即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作🤖


上成品代码:


/**
 * 使用同步机制解决售票问题的超卖现象
 */
public class TicketSalesResult {
    public static void main(String[] args) {
        SellTicketRes sellTicketRes = new SellTicketRes();
        new Thread(sellTicketRes).start();
        new Thread(sellTicketRes).start();
        new Thread(sellTicketRes).start();
    }
}
class SellTicketRes implements Runnable {
    private int ticketNum = 100;
    private boolean loop = true;
    /**
     * 使用synchronized实现线程同步,解决超卖
     */
    public synchronized void Sell() {
        if (ticketNum <= 0) {
            System.out.println("没有余票!");
            loop = false;
            return;
        }
        // 休眠卖票
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("窗口" + Thread.currentThread().getName() +
                "售出一张票。" + "剩余票数:" + (--ticketNum));
    }
    @Override
     public void run() {
        while (true) {
            if (loop == false) {
                break;
            }
            Sell();
        }
    }
}


结果分析:(完美解决超卖问题)


窗口Thread-0售出一张票。剩余票数:99
窗口Thread-0售出一张票。剩余票数:98
窗口Thread-0售出一张票。剩余票数:97
窗口Thread-0售出一张票。剩余票数:96
窗口Thread-0售出一张票。剩余票数:95
窗口Thread-0售出一张票。剩余票数:94
窗口Thread-0售出一张票。剩余票数:93
窗口Thread-0售出一张票。剩余票数:92
窗口Thread-0售出一张票。剩余票数:91
窗口Thread-0售出一张票。剩余票数:90
窗口Thread-0售出一张票。剩余票数:89
窗口Thread-0售出一张票。剩余票数:88
窗口Thread-0售出一张票。剩余票数:87
窗口Thread-0售出一张票。剩余票数:86
窗口Thread-0售出一张票。剩余票数:85
窗口Thread-0售出一张票。剩余票数:84
窗口Thread-0售出一张票。剩余票数:83
窗口Thread-0售出一张票。剩余票数:82
窗口Thread-0售出一张票。剩余票数:81
窗口Thread-0售出一张票。剩余票数:80
窗口Thread-2售出一张票。剩余票数:79
窗口Thread-2售出一张票。剩余票数:78
窗口Thread-2售出一张票。剩余票数:77
窗口Thread-2售出一张票。剩余票数:76
窗口Thread-2售出一张票。剩余票数:75
窗口Thread-2售出一张票。剩余票数:74
窗口Thread-2售出一张票。剩余票数:73
窗口Thread-2售出一张票。剩余票数:72
窗口Thread-2售出一张票。剩余票数:71
窗口Thread-1售出一张票。剩余票数:70
窗口Thread-1售出一张票。剩余票数:69
窗口Thread-1售出一张票。剩余票数:68
窗口Thread-1售出一张票。剩余票数:67
窗口Thread-1售出一张票。剩余票数:66
窗口Thread-1售出一张票。剩余票数:65
窗口Thread-1售出一张票。剩余票数:64
窗口Thread-1售出一张票。剩余票数:63
窗口Thread-1售出一张票。剩余票数:62
窗口Thread-1售出一张票。剩余票数:61
窗口Thread-1售出一张票。剩余票数:60
窗口Thread-1售出一张票。剩余票数:59
窗口Thread-1售出一张票。剩余票数:58
窗口Thread-1售出一张票。剩余票数:57
窗口Thread-1售出一张票。剩余票数:56
窗口Thread-1售出一张票。剩余票数:55
窗口Thread-1售出一张票。剩余票数:54
窗口Thread-1售出一张票。剩余票数:53
窗口Thread-1售出一张票。剩余票数:52
窗口Thread-1售出一张票。剩余票数:51
窗口Thread-1售出一张票。剩余票数:50
窗口Thread-1售出一张票。剩余票数:49
窗口Thread-1售出一张票。剩余票数:48
窗口Thread-1售出一张票。剩余票数:47
窗口Thread-1售出一张票。剩余票数:46
窗口Thread-1售出一张票。剩余票数:45
窗口Thread-1售出一张票。剩余票数:44
窗口Thread-1售出一张票。剩余票数:43
窗口Thread-1售出一张票。剩余票数:42
窗口Thread-2售出一张票。剩余票数:41
窗口Thread-2售出一张票。剩余票数:40
窗口Thread-2售出一张票。剩余票数:39
窗口Thread-2售出一张票。剩余票数:38
窗口Thread-2售出一张票。剩余票数:37
窗口Thread-2售出一张票。剩余票数:36
窗口Thread-2售出一张票。剩余票数:35
窗口Thread-2售出一张票。剩余票数:34
窗口Thread-2售出一张票。剩余票数:33
窗口Thread-2售出一张票。剩余票数:32
窗口Thread-2售出一张票。剩余票数:31
窗口Thread-2售出一张票。剩余票数:30
窗口Thread-2售出一张票。剩余票数:29
窗口Thread-2售出一张票。剩余票数:28
窗口Thread-2售出一张票。剩余票数:27
窗口Thread-2售出一张票。剩余票数:26
窗口Thread-2售出一张票。剩余票数:25
窗口Thread-2售出一张票。剩余票数:24
窗口Thread-2售出一张票。剩余票数:23
窗口Thread-2售出一张票。剩余票数:22
窗口Thread-2售出一张票。剩余票数:21
窗口Thread-2售出一张票。剩余票数:20
窗口Thread-2售出一张票。剩余票数:19
窗口Thread-2售出一张票。剩余票数:18
窗口Thread-2售出一张票。剩余票数:17
窗口Thread-2售出一张票。剩余票数:16
窗口Thread-0售出一张票。剩余票数:15
窗口Thread-0售出一张票。剩余票数:14
窗口Thread-0售出一张票。剩余票数:13
窗口Thread-0售出一张票。剩余票数:12
窗口Thread-0售出一张票。剩余票数:11
窗口Thread-0售出一张票。剩余票数:10
窗口Thread-0售出一张票。剩余票数:9
窗口Thread-0售出一张票。剩余票数:8
窗口Thread-0售出一张票。剩余票数:7
窗口Thread-2售出一张票。剩余票数:6
窗口Thread-2售出一张票。剩余票数:5
窗口Thread-2售出一张票。剩余票数:4
窗口Thread-2售出一张票。剩余票数:3
窗口Thread-2售出一张票。剩余票数:2
窗口Thread-2售出一张票。剩余票数:1
窗口Thread-2售出一张票。剩余票数:0
没有余票!
没有余票!
没有余票!
目录
相关文章
|
9天前
|
设计模式 消息中间件 传感器
Java 设计模式之观察者模式:构建松耦合的事件响应系统
观察者模式是Java中常用的行为型设计模式,用于构建松耦合的事件响应系统。当一个对象状态改变时,所有依赖它的观察者将自动收到通知并更新。该模式通过抽象耦合实现发布-订阅机制,广泛应用于GUI事件处理、消息通知、数据监控等场景,具有良好的可扩展性和维护性。
104 8
|
19天前
|
移动开发 监控 小程序
java家政平台源码,家政上门清洁系统源码,数据多端互通,可直接搭建使用
一款基于Java+SpringBoot+Vue+UniApp开发的家政上门系统,支持小程序、APP、H5、公众号多端互通。涵盖用户端、技工端与管理后台,支持多城市、服务分类、在线预约、微信支付、抢单派单、技能认证、钱包提现等功能,源码开源,可直接部署使用。
109 23
|
21天前
|
安全 前端开发 Java
使用Java编写UDP协议的简易群聊系统
通过这个基础框架,你可以进一步增加更多的功能,例如用户认证、消息格式化、更复杂的客户端界面等,来丰富你的群聊系统。
154 11
|
23天前
|
机器学习/深度学习 人工智能 自然语言处理
Java与生成式AI:构建内容生成与创意辅助系统
生成式AI正在重塑内容创作、软件开发和创意设计的方式。本文深入探讨如何在Java生态中构建支持文本、图像、代码等多种生成任务的创意辅助系统。我们将完整展示集成大型生成模型(如GPT、Stable Diffusion)、处理生成任务队列、优化生成结果以及构建企业级生成式AI应用的全流程,为Java开发者提供构建下一代创意辅助系统的完整技术方案。
105 10
|
24天前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
89 1
|
24天前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
93 1
|
27天前
|
人工智能 监控 Java
Java与AI智能体:构建自主决策与工具调用的智能系统
随着AI智能体技术的快速发展,构建能够自主理解任务、制定计划并执行复杂操作的智能系统已成为新的技术前沿。本文深入探讨如何在Java生态中构建具备工具调用、记忆管理和自主决策能力的AI智能体系统。我们将完整展示从智能体架构设计、工具生态系统、记忆机制到多智能体协作的全流程,为Java开发者提供构建下一代自主智能系统的完整技术方案。
232 4
|
27天前
|
机器学习/深度学习 分布式计算 Java
Java与图神经网络:构建企业级知识图谱与智能推理系统
图神经网络(GNN)作为处理非欧几里得数据的前沿技术,正成为企业知识管理和智能推理的核心引擎。本文深入探讨如何在Java生态中构建基于GNN的知识图谱系统,涵盖从图数据建模、GNN模型集成、分布式图计算到实时推理的全流程。通过具体的代码实现和架构设计,展示如何将先进的图神经网络技术融入传统Java企业应用,为构建下一代智能决策系统提供完整解决方案。
211 0
|
2月前
|
JavaScript Java 大数据
基于JavaWeb的销售管理系统设计系统
本系统基于Java、MySQL、Spring Boot与Vue.js技术,构建高效、可扩展的销售管理平台,实现客户、订单、数据可视化等全流程自动化管理,提升企业运营效率与决策能力。
|
2月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案