目录
1.9.2、同步方法(使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着)
2.1.3、单线程线程池(效果与定长线程池 创建时传入数值1 效果一致)
2.1.4、周期性任务定长线程池(定时执行, 当某个时机触发时, 自动执行某任务)
1、多线程:
1.1、进程
是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间
1.2、线程(分为守护线程和用户线程)
线程是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行,一个进程最少有一个线程,当一个进程启动后,里面的若干个执行路径又可以划分为若干个线程。
用户线程:当一个进程不包含任何存活的用户线程时,进行结束。
守护线程:是用来守护用户线程,当最后一个用户结束时,所有守护线程自动死亡。(setDaemon(true))。
1.3、线程的调度
分时调度
所有线程轮流使用CPU的使用权,平均分配每个线程占用的CPU的时间
抢占式调度
优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个线程,java使用的就是抢占式调度。
1.4、同步与异步
同步 排队执行,效率低但是安全
异步 同时执行,效率高但是数据不安全
1.5、并发与并行
并发:指两个或多个事件在同一个时间段内发生。
并行:值两个或多个事件在同一时刻发生(同时发生)
1.6、线程的三大特性
原子性:就是一个操作或者多个操作要么全部执行并且执行的过程中不会被任何因素打断,要么就都不执行。
可见性:当多个线程访问同一个变量时,一个线程修改这个变量值,其他线程能立刻看到修改的值。 有序性:程序的执行顺序按照代码的先后顺序执行。
1.7、开启线程的方式
1.7.1、继承Thread
重写Thread类中的run方法,但触发线程的方式不是调用run方法,而是通过Thread对象的start()来启动任务。
1.7.2、实现Runnable
这个是比较常用的,通过实现Runnable接口中的run()方法,并且在main方法中
new Thread(new MyRunnable()).start(); 来启动任务。
实现Runnable与继承Thread相比有如下优势:
(1)通过创建任务,然后给线程分配的方式来实现多线程,更适合多个线程同时执行相同的任 务。
(2)可以避免单继承带来的局限性。
(3)任务与线程本身是分离的,提高了程序的健壮性。
(4)在线程池技术中,接收Runnable类型的任务,不接受Thread类型的线程。
1.7.3、实现Callable
(1)编写类实现Callable接口 , 实现call方法
(2)创建FutureTask对象 , 并传入第一步编写的Callable类对象
FutureTask<Integer> future = new FutureTask<>(callable);
(3)通过Thread,启动线程
new Thread(future).start();
1.8、java终止线程的几种方式
1.8.1、使用标志位
注意:一定要给标志位加上volatle关键字
1.8.2、使用interrupt()方法
Interrupt()方法用于中断线程,调用该方法之后,线程状态会被置为“中断状态”,然后抛出 中断异常。但调用这种方式去终止线程会存在两种情况:
1、该线程循环执行不会存在阻塞状态
2、该线程循环执行存在阻塞状态
比如在线程中存在sleep()、await()、wait()这种能够抛出:interruptedException异常的方法,这种情况调用interrupt()方法后会将触发这些异常,可以选择在触发异常后调用break 来终止线程。
1.9、保证线程安全的三种方式
1.9.1、同步代码块
格式:
synchronized (同步锁){
需要同步操作的代码
}
1.9.2、同步方法(使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着)
格式:
public synchronized void method(){
可能会产生线程安全问题的代码
}
1.9.3、Lock锁
Lock锁也称为同步锁,只需要调用加同步锁与释放同步锁方法来保证线程安全
public void Lock();加同步锁
public void unlock();释放同步锁
注意synchronized为隐式锁,lock为显示锁
1.10、公平锁与非公平锁
1.10.1、公平锁
是指多个线程按照申请锁的顺序去获得锁,永远都是队列的第一位才能得到锁
优点:所有线程都能得到资源
缺点:吞吐量会下降很多,列队里面除了第一个线程,其他线程都会阻塞,cpu唤醒阻塞线程的 开销会很大
1.10.2、非公平锁
是指多个线程去获取锁的时候,会直接去尝试获取,获取不到,再去进入等待队列,如果能获 取到,就直接获取到锁(保证线程安全的三种方式都是非公平锁)
优点:可以减少CPU唤醒线程的开销,整体的吞吐效率会高点,CPU也不必取唤醒所有线程,会 减少唤起线程的数量。
缺点:可能会导致一些线程一直获取不到锁或长时间获取不到锁,导致饿死。
1.11、线程的六种状态
1、初始状态(new)
2、运行状态(runnable)
3、阻塞状态(blocked)
4、等待状态(waiting)
5、超时等待状态(timed_waiting)
6、终止状态(terminated)
线程的状态图:
2、线程池
如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低 系统的效率,因为频繁创建线程和销毁线程需要时间. 线程池就是一个容纳多个线程的容器,池中的线程可以反复使用,省去了频繁创建线程对象的操作,节省了大量的时间和资源。
线程池的好处
1、降低资源消耗
2、提高响应速度
3、提高线程的可管理性。
2.1、java中的四种线程池
2.1.1、缓存线程池(无限制长度)
执行流程:
1、判断线程池是否存在空闲线程池
2、存在则使用
3、不存在,则创建线程,并放入线程池,然后使用
2.1.2、定长线程池(长度是指定的数值)
执行流程:
1、判断线程是否存在空闲线程
2、存在则使用
3、不存在空闲线程,且线程池未满的情况下,则创建线程,并放入线程池,然后使用
4、不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程
2.1.3、单线程线程池(效果与定长线程池 创建时传入数值1 效果一致)
执行流程:
1、判断线程池的那个线程是否空闲
2、空闲则使用
3、不空闲,则等待池中的单个线程空闲后使用
2.1.4、周期性任务定长线程池(定时执行, 当某个时机触发时, 自动执行某任务)
执行流程:
1、 判断线程池是否存在空闲线程
2、 存在则使用
3、 不存在空闲线程,且线程池未满的情况下,则创建线程 并放入线程池, 然后使用
4.、不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程