多线程
进程与线程
-
进程
内存中运行的应用程序,每个进程内有个独立的内存空间
-
线程
进程中的一个执行路径,共享一个内存空间
线程调度
-
分时调度
平均分配每个线程占用cpu的时间
-
抢占式调度
·优先让优先级别高的线程使用CPU, java使用这个
并行和并发
- 并发:一段时间内
- 并行:同个时间
线程类
分为用户线程和守护线程(daemon)
线程有两种常见的实现方法
1.继承Thread类
重写run方法,通过Thread中的start方法运行run
- 每个线程有自己的栈空间,公用一份堆内存
2.实现一个接口Runnable
实现接口Runnable,实现run的方法
但还是得借助Thread
myRunnable r = new MyRunnable()
Thread t = new thread( r )
t.start()
-
相比于继承Thread有优势
通过创建任务,给线程分配的方式实现的多线程,适合多线程实现一个任务
可以避免单个继承带来的局限性,继承了Thread类就不能继承其他类了
任务与线程分离,提高程序健壮性
后续的线程池技术只接受Runnable类型的任务
-
线程阻塞(耗时)
-
线程中断,由线程自身决定,stop已经停用(不安全),改为打标记形式,Thread.interrupt().当遇到某些操作如sleep,会抛出异常,在catch中结束进程
线程安全
线程安全
解决方案1: 同步代码块(隐式锁)
Object o = new Object();//这个o对象作为锁必须是共有的
synchronized(锁对象){
}
解决方案2 同步方法(隐式锁)
public symchronized void A()
那么调用这个方法的时候会保证方法同步
- 如果类不是静态的,则锁对象是this
- 如果类是静态的(没有实例,没有this),则锁对象类名的字节码 Class.class
解决方法3 :显示锁Lock
Lock l = new RenntramLock()
在代码块前锁住 l.lock()
在代码块后放开 l.unlock()
公平锁和非公平锁
公平:a线程来a线程先,排队。
不公平:线程一块抢,抢到就是谁的
实现
Lock l = new RenntramLock(True)//true就是实现公平锁
多线程通信问题
class food(){
syn set(){
this.notifyall()
this.wait()
}
syn get(){
this.notifyall()
this.wait()}
}
class Cook() extend Thread{
food;
food.get;
}
class Server() extend Thread{
food;
food.set;
}
线程的6种状态
new:刚刚创建的状态,还没有启动
Runnable:在JVM中运行的线程
Blocked:排队的线程
Waiting:休眠的线程
TimedWaiting:指定了时间休眠
Terminated:线程结束
带返回值的线程Callable(第三种线程方式,上文说是两种常见创建线程方式)
class A implements callable(){
override
Interger call()
}
c = new MyCallable()
task = new futureTask<>©
new Thread(task).start()
Interger i = task.get();
主线程指派任务给Callable线程
主线程通过get获取返回值,此时main会等待task执行完。
线程池概述
一个线程数组,一个任务列表,任务列表不断加入任务,将任务分配给线程数组
- 缓存线程池 非定长,线程池里没有空闲线程可以创建
- 定长线程池 没线程池没满可以创建,,满了就得排队
- 单线程线程池
- 周期性任务定长线程池 当时机触发时,执行,可以计时
lambda
参数(int a) ->{实现},参数a