Day23-多线程
- 多线程
1.1 守护线程
1.1.1 概述
守护线程 又叫兜底线程
每个程序运行中,都会默认开启一个守护线程。当程序运行结束jvm要结束时,守护线程结束。守护线程主要用来完成垃圾回收。
可以用hread.setDameon()设置我们想要的守护线程,要在线程.start开启前设置。
1.2 Timer
- 定时器 计划任务,只要有一个任务监听 就会是一个线程
- 1 执行任务的类 , 2 执行任务起始时间 3 执行任务间隔时间(毫秒)
1.3 死锁
相关知识:如果访问一个对象中加锁的成员方法,那么该对象中其他加锁的成员方法被锁定,不能被其他线程访问。
如果访问一个类中枷锁的静态方法,那么该类中其他加锁的静态方法被锁定,不能被其他线程访问
注意:和成员无关
死锁概述:大家执行过程中互相遇到对方想进入加锁的方法,互相不放弃,导致死锁。
synchronized(xxx){} 代码块锁,可以锁类,也可以锁对象
1锁对象:访问该代码块锁的时候,该对象中其他加锁的成员方法和代码块锁不可被访问 访问对象中加锁的成员方法的时候,代码块锁也会被锁定
2 锁类: 访问该类代码块时该类中其他加锁的静态方法和加锁的代码块都不可被访问。
访问该类加锁的静态方法时,代码块锁也不可被访问。
1.4 线程通信
wait() 与 notify() 和 notifyAll()都是Object中方法,使用时要有对象且要在synchronized方法或代码块中使用。 否则会报java.lang.IllegalMonitorStateException异常
wait(): 让当前线程进入等待状态,功能依然存在,等被唤醒时继续执行。、
notify():唤醒该对象上等待的某一个线程(优先级最高的)
notifyAll(): 唤醒该对象上所有等待的线程
wait():传0或无参时,不会自动唤醒,要等被唤醒。传long类型的数值,按毫秒为单位自动唤醒。
1.4.1 面试题之生产者与消费者
思路:
一 要有一个业务类,一个成员变量(存储生产了多少件的数),一个char[] 型数组(用来保存生产出的数据)。
二 业务类有生产和消费的方法。
1 生产push:向数组添加元素,判断是否满了,如果满了,不再生产,唤醒消费者。2 消费 pop: 向数组添加元素,判断是否有数据,如果没有,唤醒生产者。
3 两个线程分别调用生产和消费
1.5 单例模式
目的:让一个类只创建一个对象
根据对象的创建时机不同,分两种:
懒汉模式 : 第一次使用的时候创建对象
饿汉模式 : 类加载的时候创建对象
思路:
1 私有化构造方法。
2 公共静态的获取对象方法。
3 私有化静态变量
1.6 线程池
1.6.1 概述
思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完 放回池中。
好处:
a)提高响应速度(减少了创建新线程的时间)
b)降低资源消耗(重复利用线程池中线程,不需要每次都创建)
c)便于线程管理
i.corePoolSize:核心池的大小
ii.maximumPoolSize:最大线程数
iii.keepAliveTime:线程没有任务时最多保持多长时间后会终止
(每个线程需要大概1MB内存,线程开的越多,消耗内存越大,最后导致死机)
- 线程池的作用 :
- 线程池作用就是限制系统中执行线程的数量
- 根据系统的环境情况,可以自动或者手动来设置线程数量,以达到运行的最佳效果
- 少了浪费系统资源,多了造成系统拥挤效率不高
- 用线程池控制线程数量,其他线程排队等候
1.6.2 使用方式
线程池相关API:ExecutorService 和 Executors
ExecutorService:真正的线程池接口。常见子类ThreadPoolExecutor
void execute(Runnable command) :执行任务/命令,没有返回值,一般用来执行Runnable
Future submit(Callable task):执行任务,有返回值,一般用来执行Callable
void shutdown() :关闭连接池
Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池
Executors.newCachedThreadPool():创建一个可根据需要创建新线程的线程池
Executors.newFixedThreadPool(n); 创建一个可重用固定线程数的线程池
Executors.newSingleThreadExecutor() :创建一个只有一个线程的线程池
Executors.newScheduledThreadPool(n):创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。