# spring-boot-multithreading **Repository Path**: zhouhengCxy/spring-boot-multithreading ## Basic Information - **Project Name**: spring-boot-multithreading - **Description**: 多线程演示 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2019-01-07 - **Last Updated**: 2023-10-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README #多线程演示 ##线程间的等待唤醒机制,JVM都是通过park和unpark命令实现的 ##一、生产者消费者问题 ###1.通过JVM的内置锁Object.wait()/Object.notify()notifyAll()/synchronized来实现 ####synchronized是为了实现同步,wait和notify、notifyAll是为了实现多线程协同处理数据 ####a.synchronized获得锁,如果获取到锁则进去方法或代码块,如果获取不到锁则阻塞 ####实例锁:synchronized(this){}作用于代码块时,是对象锁,锁的是一个实例,synchronized作用于非静态方法时默认也是对象锁 ####类锁:synchronized(class){}作用于代码块时,是类锁,锁的是该类的所有实例,synchronized作用于静态方法时,由于此时对象还未生成,所以只能采用类锁 ####对象锁:synchronized(Object){},该Object就是生产与消费模型中用于模拟仓库的list,如果对象锁跟访问的对象没有关系,那么就会都同时访问 ####由于spring boot中@service我们默认就是单例的,所以像单例的情况直接用对象锁就可以了 ####内置锁synchronized存在的问题偏向锁、轻量级锁、重量级锁、自旋锁、自适应自旋锁 https://www.jianshu.com/p/36eedeb3f912 ####b.wait线程阻塞,并释放锁 ####c.notifyAll唤醒所有阻塞的线程 ###2.通过Lock.lock()/Lock.unlock()/Condition.await()/Condition.signal()实现 ###推荐该方式,Lock.lock()就是synchronized获取锁,Lock.unlock()就是释放锁,await某个线程队列阻塞,signal释放某个线程队列 ###需要注意一定要释放锁,加锁后面跟try finally使用, ###推荐使用该方式,因为Condition可以创建多个条件队列排队,可以灵活通知某些队列线程来获取锁,还有tryLock()等方法设置时间等获取锁,得到返回true,获取失败返回false, ###以及公平与非公平锁设置来保证有些业务场景的应用,以及读写锁的优势 ####a.重入锁ReentrantLock() ####外层获得锁之后内层还要获取锁时会自动获取,这种递归的执行也不会影响锁的获取和释放称为重入锁 ####a.1公平锁和非公平锁,ReentrantLock()与ReentrantLock(false)都是非公平锁,线程获取锁不会按顺序来,ReentrantLock(true)为公平锁,线程获取锁会按照顺序来. ####大部分情况使用非公平锁,性能较好 ####b.读写锁ReentrantReadWriteLock ####读写锁,读和读不互斥以外,写和读、写和写都互斥,读写锁应用场景,就是读很多,写比较少,业务又比较敏感的场景,一般的业务都不用上撒锁的 ###3.通过BlockingQueue实现 ####查看源码可见内部实现机制与2Lock相同 ###Test类中有详细注释说明 生产者消费者问题是多线程的一个经典问题 所谓生产者-消费者问题,实际上主要是包含了两类线程, 一种是生产者线程用于生产数据, 另一种是消费者线程用于消费数据, 为了解耦生产者和消费者的关系,通常会采用共享的数据区域,就像是一个仓库, 生产者生产数据之后直接放置在共享数据区中,并不需要关心消费者的行为; 而消费者只需要从共享数据区中去获取数据,就不再需要关心生产者的行为。 但是,这个共享数据区域中应该具备这样的线程间并发协作的功能: 如果共享数据区已满的话,阻塞生产者继续生产数据放置入内; 如果共享数据区为空的话,阻塞消费者继续消费数据; ##二、真实场景-银行账户存取款 ###仿照生产者消费者模型,编写银行存取款模型 ###这里测试时一定要先启动项目app,再启动SpringBootMultithreadingApplicationTests测试类而且要注意主线程要sleep让出cpu,让其他线程能够分配cpu执行run方法 ####还有其他业务场景比如说抢票,以及高并发的秒杀系统 缓冲区可以理解为银行账户,生产为存钱,消费为取钱, 有个最高存额,以及有钱才能取,当"多线程"(例如同时操作两台ATM时), 都同时取钱,都会先查询账户余额(这个余额就是多线程同步中需要注意的共享数据), 然后都取钱操作,但是"线程同步"执行时,余额只有100,会导致,两台机器都能取出来钱。 这里跟消费者生产者还不一样,前者是仓库满了,生产出来进入堵塞,直到存入, 仓库空了,需要消费,也是进入堵塞,直到可以消费,银行这个场景,遇到上述情况直接抛异常 ##三、定时任务,执行异步线程算法评分 ###详细注解在AlgorithmTask类中