一。多线程的实现
第一种:Thread类
创建子类继承Thread类
重写run方法
run里的代码是一条新的执行路径
这个执行路径的触发方式不是调用run,而是thread子对象的start方法
每个线程都有自己的栈空间,共用一份堆内存
第二种:Runnable接口
创建子类实现Runnable接口
重写run方法
实现Runnable与继承Thread相比有如下的优势:
1.通过创建任务 给线程分配的方式来实现多线程,更适合多个线程同时执行相同任务的情况
2.可以避免单继承所带来的局限性
3.任务与线程本身是分离的,提高了程序的健壮性
4.后续学习的线程池技术,接受Runnable类型的任务,不接受Thread类型的线程
但是Thread有一个创建线程比较方便的方法
例如:
new Thread(){
@Override
public void Run(){
//线程代码
}
}.start();
二。
如何获取线程的名称
Thread.currentThread().getName();
.sleep()
Thread.sleep(200);//线程暂定200ms
三。线程的中断
一个线程是一个独立的执行路径,它是否应该结束,应该由其自身决定
中断标记 .interrupt();
四。守护线程
线程:分为用户线程和守护线程
用户线程:当一个进程不包括任何的存活的用户线程时,进程结束
守护线程:守护用户线程的,当最后一个用户线程结束时,所有守护线程自动死亡
.setDaemon(true)设置为守护线程
五。线程安全问题
解决方案一:同步代码块(隐式锁)(不公平锁)
格式:synchronized(锁对象 ){}
二:同步方法(隐式锁)(不公平锁)
格式:public synchronized void 方法名(){}
三:显式锁
格式:lock l = new ReentrantLock(默认为false);(不公平锁)
lock l = new ReentrantLock(true);(公平锁)
l.lock();
l.unlock();
显式锁和隐式锁的区别
1.出身不同 synchronized是Java中的关键字,由JVM维护,是jvm层面的锁
· lock是jdk5之后出现的具体的类,使用Lock是调用对应的API,是API层面的锁。
2.使用方式不同 synchronized是隐式锁 Lock是显式锁 显式锁需要使用者手动去获取和释放
3.等待是否中断 synchronized是不可被中断的,除非抛出异常或者正常运行结束
而Lock是可以中断的,中断方式:
1调用设置超时方法tryLock()2.调用lockInterruptibly()放到代码块中,然后调
用interrupt()方法可以中断
4.加锁的时候是否公平
synchronized是非公平锁,而lock两者都可以,默认创建是非公平锁。
5.锁绑定多个条件来condition
synchronized要么随机唤醒一个线程:要么是唤醒所有等待的线程
lock:可以用实现分组唤醒需要唤醒的线程,可以精确的唤醒,而不需像ynchronized那
样,不能精准唤醒线程。
6.性能方面synchronized在jdk1.5中性能低于lock,在jdk1.6之后并不比lock差
六。公平锁与不公平锁
公平锁:先来先到
非公平锁:线程一起抢
七。线程死锁
八。多线程通信
九。线程的六种状态
new
尚未启动的线程处于此状态。
runnable
在Java虚拟机中执行的线程处于此状态。
blocked
被阻塞等待监视器锁定的线程处于此状态。
waiting
无限期等待另一个线程执行特定操作的线程处于此状态。
timed waiting
正在等待另一个线程执行最多指定等待时间的操作的线程处于此状态。
terminated
已退出的线程处于此状态。
十。带返回值的线程Callable
- 编写类实现Callable接口 , 实现call方法
class XXX implements Callable {
@Override
public call() throws Exception {
return T;
}
}
- 创建FutureTask对象 , 并传入第一步编写的Callable类对象
FutureTask future = new FutureTask<>(callable);
- 通过Thread,启动线程
new Thread(future).start();
Runnable 与 Callable的相同点
都是接口
都可以编写多线程程序
都采用Thread.start()启动线程
Runnable 与 Callable的不同点
Runnable没有返回值;Callable可以返回执行结果
Callable接口的call()允许抛出异常;Runnable的run()不能抛出
获取返回值get()方法会阻塞主进程
.isDone()线程是否执行完毕
.cancel() 取消线程 返回Boolean类型数据
十一。线程池
1.缓存线程池(长度无限制)
执行流程:1.判断线程池是否有空闲线程 2.有就使用 3.没有就创建线程,然后使用
2.定长线程池(长度是指定的)
执行流程:1.判断线程池是否有空闲线程 2.有就用 3.没有且线程池没满的情况下就创建线程,并放入线程池 然后使用 4.如果没有空闲线程且线程池满了就等待。
3.单线程线程池
执行流程:1.判断,这个线程池里的这个线程是否空闲 2.空闲就用 3.不空闲就等待。
4.周期性任务定长线程池
执行流程:1.判断线程池是否有空闲线程 2.有就用 3.没有且线程池没满的情况下就创建线
程,并放入线程池 然后使用 4.如果没有空闲线程且线程池满了就等待。
定时执行: .schedule(runnable类型的任务,时长数字,时长数字的单位)
表示在多少时长后开始执行任务
周期执行:.scheduleAtFixedRate(runnable类型的任务,时长数字,周期时长,时长数
字的单位)
表示在多少时长之后开始执行,接下每多少周期时长执行下一次
十二。lambda表达式
对于接口或者父类的使用可以用lambda表达式替换: () -> {表达式}