1.前一天重点内容复习
创建线程使用接口实现比使用继承实现的优势
1.面向接口编程,谁实现接口谁具有功能,但是继承方式实现却有了很多不需要的功能,具有局限性
2.从内存角度考虑,接口是多个线程操作一个对象,但是继承是多个线程各自操作各自的对象,数据不共享
3.继承使用静态代理模式,可以让真实角色更专注的完成自己的事情,让代理去实现一些扩展的功能,增强了真实角色的功能
静态代理模式
真实角色和代理角色都需要实现同一个接口
多线程安全问题的标准及解决
判断多线程是否存在安全问题的标准
1.是否存在多线程环境
2.是否存在共享数据
3.是否有多条语句对共享数据进行操作
解决安全问题
1.锁对象,当一个对象正在修改数据,其他对象无法访问
synchronized(锁对象){
对共享数据进行的操作
}
2.同步代码块
3.Lock锁,子实现类ReentrantLock为可重入的互斥锁
void lock():获取锁
void unlock():释放锁
同步方法
如果一个成员方法中,方法体为同步代码块,优化为同步方法,将synchronized放置在方法声明上,格式如下:
public synchronized 返回值类型 方法名(参数列表){
同步代码块
}
同步方法和静态的同步方法锁对象是什么
同步方法需要具体对象来访问,是成员方法,这个对象为this
静态同步方法,和类相关,随着类的加载而加载,优先于对象存在,这个对象为当前类型的class属性
sleep和wait方法的区别
方法来源不同
sleep来源于Thread类
wait/notify来源于Object类
是否会释放锁
sleep属于线程方法,不会对锁进行操作
wait属于锁对象调用,调用时会释放锁
抛出异常均为中断异常
2.死锁
当多线程使用同步代码块或者lock锁解决安全问题时,会出现死锁现象
死锁就是当多个线程操作不是同一个子类对象,可能造成线程相互等待的情况
解决死锁问题可以使用生产者和消费者模式思想,生产者消费者必须使用同一个资源类对象,生产者和消费者之间需要使用等待唤醒机制,生产者生产出数据需要等待消费者将其消费掉之后,才能生产下一个数据
3.传统线程创建方式和线程池创建线程方式的不同
传统线程创建的方式为创建线程对象,这些线程对象在用户线程中,这些线程的线程组就是在main方法中,当这些线程使用完毕之后,就被GC回收了,释放了内存
线程池为创建一些固定的,可重用的线程,使用时创建,不使用时归还给线程池,等待下一次利用
4.线程池
存储若干个固定且可重用的线程
工厂类Executors
public static ExecutorService newFixedThreadPool(int nThreads):建一个线程池,该线程重用固定数量的线程
接口ExecutorService:线程池
<T> Future<T> submit(Callable<T> task):提交值返回任务以执行
返回值future是接口,异步任务计算结果
形参Callable是一个接口
call方法计算结果
void shutdown():有序关闭线程
5.线程池参数
核心线程数量,最大线程数量,拒绝策略,创建新线程对象的激活时间,创建线程对象,工作队列