多线程
线程是一个程序内部的一条执行流程
多线程的好处————消息通信,网页浏览等等
多线程是指从软硬件上实现多条执行流程的技术
并发和并行同时执行
多线程的创建
Java.Long包下的Thread类
定义一个子类继承Tread,重写run方法(方法里面是另一个线程),再在主程序中创建子类的对象,调用start()方法
优点:编码简单
缺点:线程类已经继承Tread,无法继承其他类,不利于功能扩展
注意事项:1 启动线程时必须调用start()方法,2 不要把主线程任务放在启动子线程之前
实现Runnable接口
线程创建方式一:定义一个子类实现Runnable,重写run方法(方法里面是另一个线程),再在主程序中创建子类的对象,调用start()方法
优点:任务类只是实现接口,可以继续继承其他类,实现其他接口,扩展性强
缺点:~~需要多创建一个Runnable对象
线程创建方式二:匿名内部类的创建方式
实现Callable接口
前面两种线程创建方式存在一个无返回值的问题
利用Callable接口和FutureTast类来实现:创建任务对象--->步骤一:定义一个类实现Callable接口,重写call方法,封装要做的事情,和要返回的数据。把Callable类型的对象封装成FurureTast(线程任务对象)。步骤二:把线程任务对象交给Thread对象后调用start()方法
优点:直接返回线程执行完成的结果
缺点:编码复杂
线程的常用方法
run()
线程的任务方法
start()
启动线程
getName()
获取当前线程抿成,默认为Thread-索引
setName()
设置线程名称
currentThread()
获取当前执行的线程对象
sleep(休眠多少毫秒)
休眠多少毫秒后继续执行
join()
让调用当前这个方法的线程先执行完
线程安全
发生原因:多个线程同时访问同一个共享资源,且存在修改该资源
解决方法:
线程同步
让多个线程实现先后依次访问共享资源
方案一:加锁
实现方法一:同步代码块
作用:把访问共享资源的核心代码上锁
原理:每次只允许一个线程加锁后进入,执行完毕之后自动解锁
注意事项:同步锁必须是同一把;锁的使用最好使用this;如果时静态方法时,建议使用类名.class来代表锁
实现方法二:同步方法
作用:把访问共享资源的核心方法上锁
原理:每次只允许一个线程进入方法;如果方法是实例方法:同步方法默认使用this作为锁对象;如果方法是静态方法:同步方法默认使用类名.class作为锁对象
实现方法三:Lock锁
方便于手动解锁和上锁:Lock lk = new ReentrantLock
lk.lock 和 lk.unlock
注意事项:放在一个try{}cath{}final{}里面,保证中间代码出现错误时,能够及时解锁
线程通信
解释:当多个线程共同操作共享资源是,线程间通过某种方式互相告诉自己的状态,相互协调,避免无效的资源争夺
常见模型
生产者与消费者模型
生产者线程负责生产数据
消费者线程负责消费生产者产生的数据
注意:生产者生产完数据应该等待自己,通知消费者;消费者消费完数据也应该等待自己,再通知生产者生产!
线程池
解释:线程池是一个可以复用线程的技术
好处
降低资源消耗:通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
提高响应速度:当任务到达时,可以不需要等待线程创建就能立即执行。
提高线程的可管理性:线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,监控和调优。
线程池的的创建:ExecutorService接口
ThreadPoolExecutor(核心线程数量,线程池最大线程数量,临时线程的存活时间,临时线程存活单位(秒、分、时、天),线程池任务队列,指定线程池的线程工厂,指定线程池的任务拒绝策略)==========七个参数
常用方法:
execute()执行Runable任务
submit()执行Callable任务,返回未来对象,用于获取线程返回的结果
shutdown()等全部任务执行完毕后关闭线程池
shutdownNow() 立即关闭线程池,停止正在执行的任务,并返回队列中未执行的任务。
Excutors类调用方法:Executors.newFixedThreadPool()
常用方法
newFixedTheradPool() 创建固定线程数量的线程池,如果某个线程应为执行异常而结束,那么线程池会补充一个新线程替代他。
newSingleThreadexcutor()创建只有一个线程的线程池对象,如果该线程出现异常而结束,那么线程池会补充一个新的线程
newCachedThreadPool()线程数量随着任务增加而增加,如果线程任务执行完毕且空闲了60秒则会被回收掉
newScheduledThreadPool()创建一个线程池,可以实现在给定的延迟后运行任务,或者定期执行任务。
可能出现风险:大型并发系统环境中使用Excutors如果不注意可能会出现风险
临时线程创建规则:新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程
拒绝新任务规则:核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始拒绝任务。
核心线程数量的配置方法: 计算密集型的任务: 核心线程数 = CPU的核数+1 IO密集型的任务: 核心线程数 = CPU核数 x 2
===========================多线程语法思维导图=============================