首页 > 其他分享 >多线程练习(卖票和转账)

多线程练习(卖票和转账)

时间:2023-12-20 23:01:37浏览次数:31  
标签:转账 java 卖票 money int amount 线程 多线程 public

买票练习

@Slf4j(topic = "c.ExerciseSell")
public class ExerciseSell {
    public static void main(String[] args) throws InterruptedException {
        // 模拟多人买票
        TicketWindow window = new TicketWindow(1000);

        // 所有线程的集合
        List<Thread> threadList = new ArrayList<>();
        // 卖出的票数统计
        List<Integer> amountList = new Vector<>();
        for (int i = 0; i < 2000; i++) {
            Thread thread = new Thread(() -> {
                // 买票
                int amount = window.sell(random(5));
                // 统计买票数
                amountList.add(amount);
            });
            threadList.add(thread);
            thread.start();
        }

        for (Thread thread : threadList) {
            thread.join();
        }

        // 统计卖出的票数和剩余票数
        log.debug("余票:{}", window.getCount());
        log.debug("卖出的票数:{}", amountList.stream().mapToInt(i -> i).sum());
    }

    // Random 为线程安全
    static Random random = new Random();

    // 随机 1~5
    public static int random(int amount) {
        return random.nextInt(amount) + 1;
    }
}

// 售票窗口
class TicketWindow {
    //此时 count是共享变量
    private int count;

    public TicketWindow(int count) {
        this.count = count;
    }

    // 获取余票数量
    public int getCount() {
        return count;
    }

    // 售票 加上synchronized 同一时刻只有一个线程可以访问此线程
    public synchronized int sell(int amount) {
        if (this.count >= amount) {
            this.count -= amount;
            return amount;
        } else {
            return 0;
        }
    }
}

将上面代码的Vector改为ArrayList,是否会出现线程安全问题?

输出如下

22:09:36.690 c.ExerciseSell [main] - 余票:0
Exception in thread "main" java.lang.NullPointerException
	at cn.itcast.n4.exercise.ExerciseSell.lambda$main$1(ExerciseSell.java:37)
	at java.util.stream.ReferencePipeline$4$1.accept(ReferencePipeline.java:210)
	at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.IntPipeline.reduce(IntPipeline.java:457)
	at java.util.stream.IntPipeline.sum(IntPipeline.java:415)
	at cn.itcast.n4.exercise.ExerciseSell.main(ExerciseSell.java:37)

由于arrayList并不是线程安全的,多个线程调用add方法会导致线程安全问题

Vector是线程安全的集合所以没有此问题

转账练习

public static void main(String[] args) throws InterruptedException {
        //注意有A B两个账户
        Account a = new Account(1000);
        Account b = new Account(1000);
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                a.transfer(b, randomAmount());
            }
        }, "t1");
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                b.transfer(a, randomAmount());
            }
        }, "t2");
        t1.start();
        t2.start();
        //等待两个线程执行完毕
        t1.join();
        t2.join();
        // 查看转账2000次后的总金额
        log.debug("total:{}", (a.getMoney() + b.getMoney()));
    }

    // Random 为线程安全
    static Random random = new Random();

    // 随机 1~100
    public static int randomAmount() {
        return random.nextInt(100) + 1;
    }
}

// 账户
class Account {
    //money是共享变量
    // 账户余额
    private int money;

    public Account(int money) {
        this.money = money;
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }

    // 转账
    public void transfer(Account target, int amount) {
        //由于a,b是两个对象,两个对象都要加锁,所以要加类锁
        synchronized (Account.class) {
            if (this.money >= amount) {
                this.setMoney(this.getMoney() - amount);
                target.setMoney(target.getMoney() + amount);
            }
        }
    }

单个对象使用对象锁,多个对象并发修改的情况下使用类锁

标签:转账,java,卖票,money,int,amount,线程,多线程,public
From: https://blog.51cto.com/AmbitionGarden/8911399

相关文章

  • C++11 多线程
    文章参考:C++教程|爱编程的大丙(subingwen.cn)C++11的原子量与内存序浅析-兔晓侠-博客园(cnblogs.com)从C++11起,C++为用户提供一套新的多线程类。线程相关操作头文件:thread#include<thread>一.std::thread1.初始化和析构默认构造函数:原型:thread()noexce......
  • 多线程
    sleep方法:sleep方法使当前线程暂停执行指定的时间,然后继续执行。在线程休眠期间,它不会释放任何锁资源。sleep方法主要用于控制线程的执行速度或等待某个条件成立。Thread.sleep(5000);//休眠5秒钟Threadt1=newThread(newRunnable(){@Overridepubl......
  • 【多线程笔记】Channel
    在面对生产者-消费者的场景下,netcore提供了一个新的命名空间System.Threading.Channels来帮助我们更高效的处理此类问题,有了这个Channels存在,生产者和消费者可以各自处理自己的任务而不相互干扰,有利于两方的并发处理,这篇文章我们就来讨论下如何使用System.Threading......
  • Python多线程应用于自动化测试操作示例
    本文实例讲述了Python多线程应用于自动化测试操作。分享给大家供大家参考,具体如下:多线程执行测试用例实例:importthreadingfromtimeimportsleep,ctimefromseleniumimportwebdriver#测试用例1deftest_baidu(browser,search):print("开始,现在时间是%s"%ctime())print("......
  • linux 使用 mwget 实现多线程下载
    mwget和curl/multicurl一样,m就是multi多线程的意思。mwget是wget的升级版,支持多线程下载【使用方法】gitclonehttps://github.com/rayylee/mwget.gitcdmwgetyum-yinstallpkg-configyum-yinstalllibssl-devyum-yinstallintltool./configuremake&&makeins......
  • Java | 多线程并发编程CountDownLatch实践
    关注:CodingTechWork引言  在一次数据割接需求中,数据需要通过编程的方式进行转移割接到新平台,此时若串行化方式,无疑会拉锯此次战斗,所以首当其冲要使用并发编程来降低割接时长。  本次主要考虑使用CountDownLatch工具类进行并发编程的控制。CountDownLatch概述  在并发编程过程......
  • 关于python http.server 开启多线程并发的问题
    问题描述thon中的http.server模块是单线程的,这意味着它一次只能处理一个请求,而其他请求必须等待。为了解决这个问题,您可以考虑使用多线程或异步处理来处理并发请求。您可以使用Python的ThreadingMixIn来创建一个支持多线程的HTTP服务器,或者考虑使用异步框架如asyncio来处理请求......
  • 多线程+信号量同步线程
    实现场景:多线程+信号量实现线程同步执行线程在创建的时候并不能保证优先顺序,是异步的,如果想按照自己指定的顺序先后执行的话,可以使用一些互斥或者同步的方式;以下我是通过信号量来实现同步:信号量的类型是sem_t,需要的头文件是 #include<semaphore.h>,主要是方法是sem_init......
  • C#:多线程篇
    文章目录基础概念进程线程句柄多线程同步/异步C#中的多线程Thread如何开启新线程线程的停止等待后台线程,前台线程跨线程操作主线程UI线程的优先级扩展封装数据槽内存栅栏资源竞争与线程锁ThreadPoolThreadPool好处线程池如何分配一个线程线程等待线程池如......
  • Python多线程编程:竞争问题的解析与应对策略
    本文将深入探讨Python多线程编程中可能出现的竞争问题、问题根源以及解决策略,旨在帮助读者更好地理解、应对并发编程中的挑战。多线程竞争问题的复杂性源自于对共享资源的并发访问和操作。在不同线程间的交叉执行中,共享资源可能因无序访问而导致数据不一致、死锁或饥饿等问题。解决......