Java EE初阶 --多线程1
一.wait() 和 notify()
作用:由于多线程是抢占式执行,这俩个方法可以协调多个线程之间的执行顺序
属于Object类下的的方法,由于是所有对象的父类,则每个对象都继承了该方法
1.wait()
功能:
1)使调用者所在线程暂时放弃该线程的锁,进行到等待队列(不会继续竞争这个锁)进行等待,想放弃哪个锁(对象)就由该锁调用。
2)必须在加锁的条件(即synchronized代码块中)下使用,毕竟只有有锁的情况下才可以暂时放弃锁,否者就会报错
3)满足一定条件会被唤醒,一般使用 notify() 方法进行唤醒,但也有可能被interrupt()唤醒抛出异常
正常唤醒后就会把线程重新进入到阻塞队列中竞争锁(被唤醒后不会立马获得锁,得和其他线程竞争,拿到锁后才会继续执行执行,如果是interrupt唤醒则拿到锁后才会抛出异常)
4)有超时间版本,可以传入等待时间,等到一定时间就会放弃等待,进入到阻塞队列竞争锁
2.notify()
功能:
1)可以唤醒一个呈wait状态的线程(线程调用哪个对象的notify,就随机唤醒使用该队象调用wait的线程,而不是随便唤醒一个线程),一次notify只能唤醒一个wait
2)该方法也得在synchronized代码块中使用
3)需要在有其他线程调用wait方法后使用才有效果,否则调用无效(空操作)
4)notify() 方法调用本身并不会释放锁。调用线程在发出通知后将继续持有锁,并执行同步块内剩余的代码。只有当调用线程退出同步块后,锁才会被释放。
3.notifyAll()
功能:
唤醒所有呈wait状态的线程,是他们(已经调用wait的对象所在的线程)重新回到阻塞队列中去竞争该对象锁
4. 使用

二.wait和sleep的对比(面试题)
1.wait需要搭配synchronized使用,而sleep不需要
2.wait在synchronized内会释放锁,而sleep不会,会抱着锁睡
3.wait是Object下的方法,sleep是Thread类下的静态方法。
三.设计模式
1.啥是设计模式?
相当于棋谱,无论怎么下棋,大部分都比自学的好很多。软件开发中也有很多常见的"问题场景".针对这些问题场景,⼤佬们总结出了⼀些固定的套路.按照这 个套路来实现代码,也不会吃亏.
2.单例模式
单例模式是设计模式中的其中一种,该模式有很多实现方式,主要实现方式有 “饿汉” 模式和“懒汉”模式。
强制要求:该模式下,只能有一个实例对象,不允许创造多个实例,即不能new多次,否者会报错
2.1 饿汉模式

2.2 懒汉模式

3.俩种单例模式的区别
1.饿汉模式是类加载时就创建实例,而懒汉模式是调用时创建,不用就不创建。
2.以上实现方式,饿汉模式只有return这个读操作,涉及不到线程安全问题。而懒汉模式涉及条件判段和、读取数据和写入数据操作,可能涉及线程安全问题。
4.懒汉模式的优化

四.阻塞队列
1.什么是阻塞队列?
阻塞队列是⼀种特殊的队列.也遵守"先进先出"的原则. 阻塞队列能是⼀种线程安全的数据结构,并且具有以下特性:
• 当队列满的时候,继续入队列就会阻塞,直到有其他线程从队列中取走元素.
• 当队列空的时候,继续出队列也会阻塞,直到有其他线程往队列中插入元素.
阻塞队列的一个典型的开发场景就是 “ 生产者消费者模型 ”
2.什么是“ 生产者消费者模型 ”?
2.1 图形举例

2.2 优缺点

3.标准库的阻塞队列
在Java的标准库中实现了对阻塞队列的封装类,可以直接拿出来使用,不用自己实现
• BlockingQueue是⼀个接口,实现该接口的有很多个类,举例如下:

• put方法用于阻塞式的⼊队列,take用于阻塞式的出队列.
• BlockingQueue也有offer,poll,peek等方法,但是这些方法不带有阻塞特性.
3.1阻塞队列类的使用:

3.2生产消费者模型的使用

3.3 补充知识
10亿字节为1GB,百万字节为1MB,一千字节为1KB,如果在上述生产者消费者模型不设置容量,给消费者每次消费就休眠一秒,无论运行到何时都不会挂,因为该队列最多存储21亿个int,即80亿个字节,也就是8GB,而我电脑内存为24GB,不会超出。
一个JVM进程不一定能使用机器所有的内存,可以在JVM运行的时候可以设置参数指定JVM最多最多消耗多少内存,当实际消耗内存超过最大消耗内存就会挂
4.阻塞队列的模拟实现

五.定时器
1.定时器是什么?
可以设置某个时间执行一段代码,标准库提供了Timer类来达到该效果,其核心方法是schedule
使用:

2.定时器的模拟实现

六.线程池
1.什么是线程池?
线程池是一个存放和管理线程的容器,它会把一些线程放入这个容器里,在应用程序启动或初始化阶段就创建,想要执行任务时,就把任务传到工作队列(阻塞队列),由其中一个线程执行,执行完后就会恢复到等待状态,不会销毁线程。
2.线程池的创建
Java标准库提供了创建线程池的类ThreadPoolExecutor,通过submit方法来传递任务。
2.1 ThreadPoolExecutor的构造方法参数解析

2.2 Executors类
由于上述ThreadPoolExecutor类创建线程池太过于麻烦,所以Java标准库对此类进行了封装
Exectors就是对ThreadPoolExecutor类的封装,其也涉及到工厂模式,通过静态方法来创建不同需求的线程池,这些方法返回了实现了ExexutorService接口的线程池的实例,静态方法如下:
newFixedThreadPool:创建固定的线程数,即线程核心数和最大线程数一样,不能动态增长线程数
newCachedThreadPool:创建线程数目动态增长的线程池
newSingleThreadExecutor:创建只包含单个线程的线程池
newScheduledThreadPool:也是创建固定的线程数,但可以安排任务在延迟的时间(即指定时间)后执行,时间最早的先执行,通过schedule来提交任务和设置时间。
使用:

2.3 线程池的模拟实现

更多推荐



所有评论(0)