多线程
线程:是操作系统能够进行运算调度的最小单位。他被包含早进程中,是进程中的实际运作单位。
简单理解:应用软件中互相独立、能够同时运作的功能
作用:提高运行效率
应用场景:软件中的耗时操作、聊天软件、后台服务器(只要想让多个事情同时运行,就需要多线程)
并行和并发
并发:
//在同一时刻,有多个指令在单个CPU上交替执行
并行:
//在同一时刻,有多个指令在多个CPU上同时执行
多线程的实现方式
1、继承Thread类的方式进行实现
1、自己定义一个类继承Thread类;
2、重写run方法;
3、创建子类对象,并启动线程
2、实现Runnable接口的方式进行实现
1、自己定义一个类实现Runnable接口;
2、重写run方法;
3、创建自己类的对象;
4、创建一个Thread对象,并开启线程
3、利用Callable接口和Future接口方式实现
1、自己定义一个类实现Callable接口
2、重现call方法
3、创建自己类的对象(表示多线程要实现的任务)
4、创建FutureTask对象(作用管理多线程运行的结果)
5、创建Tread对象,开启线程
常用成员方法
String getName();//返回此线程的名称
如果没有设置名字,有默认的线程名字:Thread-X(X是序号,从0开始)
void setName(string name);//设置线程的名字(构造方法也可以设置
static Thread currentThread();//获取当前线程的对象
static void sleep(long time);//让线程休眠指定的时间,单位为毫秒
哪个线程执行到这里就会停留对应的时间,
setPriority(int newPriority);//设置线程的优先级,优先级越高,抢到CPU的概率越高
优先级分为:1~10,默认为5
final int getPriority();//获取线程的优先级
final void setDaemon(boolean on);//设置为守护线程
当非守护线程结束后,守护线程会陆陆续续的结束(备胎线程)
public static void yield();//出让线程/礼让线程
public static void join();//插入线程/插队线程
线程的生命周期
创建–>就绪–>运行代码–>死亡
运行阶段遇到sleep()会进入阻塞阶段
阻塞结束会再次进入就绪阶段,进行CPU的抢夺
同步代码块
把操作共享的代码锁起来
格式:
synchronized(锁对象){//注意:锁对象一定是唯一的,一般使用本类的字节码文件,即类名.class
操作共享的代码
}
特点1;锁默认打开,有线程进去,锁自动关闭
特点2;里面的代码全部执行完毕,线程出来,锁自动开启
同步方法
就是把synchronized关键字加到方法上
将同步代码块的内容提取到方法即可
格式:
修饰符 synchronized 返回值类型 方法名 (参数){...}
特点1:同步方法是锁住方法里的所有代码
特点2:锁对象不能自己指定:
静态:this
非静态:本类的字节码文件对象
Lock接口:
不能直接创建对象,需要创建实现类ReenTrantLock对象
方法:
lock()//上锁
unlock();//释放锁(通常写在Finally里)
与synchronized相比:不如synchronized便捷,但是比synchronized更灵活,可操作性强
注:不要让两个锁嵌套,会形成死锁
生产者和消费者(等待唤醒机制)
生产者消费者模式是一个十分经典的多线程协作模式
常见方法
void wait();//当前线程等待,只到被其他线程唤醒
void notify();//随机唤醒单个线程
void notify();//唤醒所有线程
阻塞队列方法实现
生产者和消费者必须使用同一个阻塞队列
使用Array BlockingQueue阻塞队列实现
线程的状态
新建状态(NEW)—>创建线程对象
就绪状态(RUNNABLE)—>start方法
阻塞状态(BLOCKED)—>无法获取锁对象
等待状态(WAITING)—>wait方法
计时等待(TIMED_WAITING)—>sleep方法
结束状态(TEMRINATED)—>全部代码运行结束
线程池
主要原理:
1、创建一个池子,池子中是空的
2、提交任务时,池子会创建一个新的线程,任务执行完毕,线程归还池子,下次再提交任务时,不需要创建新的线程,直接复用已有的线程即可
3、但是如果提交问题时,池中没有空余线程,也无法创建新的线程,任务只能排队等待
代码实现:
1、创建线程池:
Executors:线程池的工具类通过调用方法返回不同类型的线程池;
public static ExectorsService newCachedThreadPool();//创建一个没有上限的线程池
public static ExectorsService newFixedThreadPool(int nThreads);//创建一个有上限的线程池
2、提交任务
void submit(线程对象);//提交任务
3、所有任务完成,关闭线程池
void shutdown();//销毁线程池
自定义线程池
1、创建一个空的池子
2、有任务提交时,线程池会创建线程去执行任务,执行完毕归还线程
不断的提交任务,会有以下三个临界点:
1、当核心线程满时,再提交任务就会排队
2、当核心线程满,队伍满时,会创建临时线程
3、当核心线程满,队伍满,临时线程满时,会触发任务拒绝策略
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor()
//(核心线程数量,最大线程数量,空闲线程最大存活时间,任务队列,创建线程工厂,任务的拒绝策略);
//参数一:核心线程数量 不能小于0
//参数二:最大线程数 不能小于0,最大数量 >= 核心线程数量
//参数三: 空闲线程最大存活时间 不能小于0
//参数四:时间单位 用TimeUnit指定
//参数五:任务队列 不能为nu11
//参数六:创建线程工厂 不能为nul1
//参数七:任务的拒绝策略 不能为nu11
最大并行数:指电脑的线程数
CPU密集型运算:最大并行数+1
I/O密集型运算:最大并行数 * CPU期望利用率 * (总时间(CPU计算时间+等待时间) / CPU计算时间 )