复习
线程安全问题
原因 : 多个线程同时操作同一个数据导致的
解决思路 : 保证同时只能有一个线程操作数据
解决方案 :
方案一 : 同步代码块
语法
synchronize(锁对象){ 要同步的代码 }注意 :
1.任何一个类的对象都可以作为锁对象
int a = 11;可以 char c = 'a';可以
Student stu = new Student();stu也可以
2.保证多个线程的锁对象是同一个对象
方案二 : 同步方法
语法
访问权限修饰符 synchronize 返回值类型 方法名(形参列表){ 方法体 }注意 :
1.同步方法的锁对象就是调用该方法的对象,简称this 2.保证多个线程的锁对象是同一个对象(同一个对象调用)
方案三 : 同步静态方法
语法 :
访问权限修饰符 synchronize static 返回值类型 方法名(形参列表){ 方法体 }注意 :
1.同步静态方法的锁对象是该类的类对象 2.保证多个线程的锁对象是同一个对象
类对象 : 当类被加载时会生成一个对应的对象,该对象包含该类的所有信息,如属性,方法,构造函数,类名,父类,实现的接口,所在的包等所有信息,该对象被称为该类的类对象.一个类只有一个类对象
死锁 (主动规避)
原因 : 多个线程互相抢夺对方需要的锁资源
如何避免 : 尽量不在同步中使用同步
线程间通讯
注意 :
1.线程间通讯的方法由Object提供
2.必须在同步中使用
3.必须使用所在同步的锁对象调用 (用锁对象调用方法)
提供的方法
notify() :
随机唤醒一个线程,使用同一个对象进行休眠的线程
notifyAll() :
唤醒所有线程,使用同一个对象进行休眠的线程
wait() :
无限期休眠
wait(int ms) :
有限期休眠 ms : 毫秒
wait(int ms,int ns) :
有限期休眠 ns : 纳秒
wait和sleep的区别 :
1.wait在休眠期间会释放所持有的锁资源 ,sleep不会
2.wait必须在同步中使用,sleep可以在任何一处使用
3.wait必须使用锁对象调用,sleep使用Thread类或Thread的子类对象调用
4.wait由Object提供,sleep由Thread提供
生产者与消费者模式
设计模式主要是编程人员对特定问题总结出的最优解决思路
主要解决的是工厂的进销存业务
今日
线程池 (重点)
作用 : 优化线程
为什么优化
一个线程大约占1MB的运行内存
大量创建线程时可能会导致内存溢出
大量的创建线程也导致,需要对象线程频繁创建与回收
优化思路(或想法)
用空闲的线程执行新的任务 (线程的复用)
设计一个容器来管理线程的创建,回收,复用等
(注意 : java中已经有线程池来实现以上操作)
线程池的体系结构
构造函数
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)corePoolSize : 核心线程数,线程池中最少有几个线程
maximumPoolSize : 最大线程数,线程中最多可以容纳几个线程
keepAliveTime : 销毁时间,当线程执行完任务后,多久销毁
unit : 时间单位
workQueue : 存储执行的线程任务的集合(队列形式)
threadFactory : 创建线程
handler : 优化线程,使其线程复用的算法
Excutors
作用 : 创建线程池
ThreadPoolExecutor过于麻烦
此时有个靓仔写了Excutors类,用来创建线程池,由上图不难看出,返回值是创建线程池的类的对象
提供的方法
1.固定线程池
特点 :
线程池中的线程数量恒定
当线程任务小于线程数量时,随机在线程池中挑选线程执行任务.
当线程任务大于线程数量,会先执行前面的任务,后等前面任务执行完毕后,使用执行完毕的线程,执行剩余任务
static ExecutorService newFixedThreadPool(int nThreads)
nThreads : 线程池中线程的数量
2.可变线程池
特点 : 线程池中的线程数量可变
static ExecutorService newCachedThreadPool()
3.单例线程池
特点 : 一个线程池中只有一个线程
static ExecutorService newSingleThreadExecutor()
4.抢占线程池(了解)
特点 : JDK1.8出现
static ExecutorService newWorkStealingPool()
5.调度线程池
特点 : 该线程池执行任务可以延迟,也可以延迟重复执行
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
corePoolSize : 线程池中线程的数量
6.单例调度线程池
特点 : 调度线程池中只有一个线程
static ScheduledExecutorService newSingleThreadScheduledExecutor()
线程池使用
步骤 :
1.创建线程池
2.提交任务
3.关闭线程池 (注意要关闭)
调度线程池
ScheduledExecutorService
提供的方法
public ScheduledFuture<?> schedule(线程任务, long delay, TimeUnit unit)作用 : 延迟执行
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);作用 : 延迟重复执行
1参 : 执行的任务
2参 : 延迟时间
3参 : 间隔时间
4参 : 时间单位
注意 :
间隔时间为本次任务开始时间 - 上次任务开始时间
如果上次任务执行时间>间隔时间,那么当上次任务执行完毕后,本次任务直接开始
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);作用 : 重复执行
1参 : 执行的任务 2参 : 延迟时间 3参 : 间隔时间=本次任务开始时间-上次任务结束时间 4参 : 时间单位
Callable
优化线程任务的
作用 : 有返回值的线程任务对象
注意 : 无法在创建Thread对象时传入,必须配合线程池使用(和线程池绑在一起的)
Lock
优化锁对象
作用 : 简化同步
对比同步
同步代码块
synchronize(锁对象){ //进入这里就是关锁 代码 //同理进入这里就是开锁(释放所资源) }
同步方法
访问权限修饰符 synchronize 返回值类型 方法名(形参列表){ //进入这里就是关锁 方法 //同理进入这里就是开锁(释放所资源) }
同步静态方法
访问权限修饰符 synchronize static 返回值类型 方法名(形参列表){ //进入这里就是关锁 方法 //同理进入这里就是开锁(释放所资源) }
Lock体系
Lock 提供的方法: void lock():关锁 void unLock():开锁 Condition newCondition():获取锁对象 void await():无限期休眠 void signal():随机唤醒一个 void signalAll():唤醒所有 子类: ReentrantLock ReadWriteLock 提供的方法: Lock readLock():获取读锁 Lock writeLock():获取写锁 注意: 读-写 互斥 读-读 不互斥 写-写 互斥 子类 ReentrantReadWriteLock