多线程
指从软硬件上实现多条执行流程的技术
如12306的买票系统,多个用户同时购票时,每个用户都有一个执行流程。或者百度网盘中同时上传文件和下载文件
一,多线程的创建
方式1 继承Thread类
通过java.lang.Thread类代表线程
首先自己创建线程类去继承Thread类,并重写run方法。使用时调用start()方法
image.png
缺点:继承Thread类,无法继承其他类不利于扩展
方式2 实现Runnable接口
定义一个类来实现Runnable接口,重写run方法,使用时调用start()方法
线程任务类只是实现接口,这样的写法他可以继续继承类和实现接口,扩展性好
缺点多一层对象包装,线程执行结果不可以直接返回
方式1和方式2他们重写run方法是无返回值的,不适合返回线程结果的业务场景,只能执行功能。
方式3 jdk5.0新增 实现Callable接口
解决得到线程执行结果返回
- 1 得到任务对象
- 定义类实现Callable接口,重写call方法,封装要做的事情
- 用FutrueTask把Callable对象封装成线程任务对象
- 2 把线程任务对象交给Thread处理
- 3 调用Thread的start方法启用线程
-
4 线程调用完毕后,启用FutrueTask的get方法获取任务执行结果
callable
二,线程的常用方法
- Thread.currentThread() 那个线程执行他,就调用那个线程名字
- setName() 设置线程名字
- getName()获取线程名字
- Thread.sleep()当前线程休息多长时间后执行
三,线程安全
多个线程同时操作同一个共享资源的时候出现的业务安全问题,称线程安全
如,银行卡你和你女朋友同时去取钱
出现原因:
1 存在多线程并发
2 同时访问共享资源
3 修改共享资源
线程同步可以解决这种安全问题
让多个线程实现先后顺序依次访问共享资源。
-
加锁
把共享资源进行上锁,每次只能一个线程进入访问完毕以后解锁,其他线程才能进来 -
方式1 同步代码块
把出现线程安全的核心代码块上锁
synchronized(锁对象){
//核心代码块
}
//锁对象建议使用共享资源作为锁对象
//对于实例方法可以使用this
//对于静态方法建议使用类名.class作为锁对象 -
方式2 同步方法
将出现线程安全的核心方法上锁
修饰符synchronized 返回值类型 方法名(形参){
//操作共享资源的代码
} -
方式3 Lock锁
private final Lock lock = new ReentrantLock();//final修饰不可替换
lock.lock()//上锁
lock.unlock()//解锁
最好使用try{}finally{}来使用 ,如出现异常也可以解锁
四,线程池
线程池就是一个可以复用线程的技术
不使用线程池的问题
用户每发送一个请求,后台就创建一个线程来处理,下次来了新任务还要继续创建新线程,而创建多的线程会影响性能
如有1万个人来使用这个功能,我们不可能创建1万个线程来解决
4.1 实现线程池
线程池接口ExecutorService
,需要用ThreadPoolExecutor
实现类来实现
临时线程什么时候创建?
当新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以临时创建临时线程,即创建
4.2 线程池处理Runnable任务
处理Runnable //关闭线程池
es.shutdownNow();//立即关闭,会丢失未执行的任务
es.shutdown();//等待任务执行完毕后执行
4.2 线程池处理Callable任务
callable4.3 Executor工具类实现线程池
image.png五,定时器
是一种控制任务延时调用,周期调用
方式 1 Timer定时器
缺点:
- 1 Timer定时器是单线程,处理多个任务按照顺序执行,存在延时与定时器的时间有出入
- 2 如果某个任务异常会使线程死掉,后续的任务处理不了
//1 创建timer定时器
Timer timer = new Timer();
//2 调用方法,处理定时任务
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行一次");
}
},3000,2000);//等3秒开始跑,每2秒执行一次
}
方式2 ScheduledExecutorService定时器
基于线程池
多线程处理多任务,如某一任务有问题不会影响其他任务
//创建ScheduledExecutorService线程池,做定时器
ScheduledExecutorService ses = Executors.newScheduledThreadPool(3);
//开始定时任务
ses.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"第一个任务");
}
},0,1000, TimeUnit.SECONDS);//每隔1秒跑一次
}
并发并行
正在运行的软件就是一个独立的进程,线程属于进程,多个线程并发与并行是同时进行的。
并发 (同一时间段,抢占cpu执行自己)
- cpu同时处理线程的数量是有限的
- cpu会轮询为系统每个线程服务,切换速度很快,让我们感觉是同时执行的,这就是并发
在同一时刻,同时有多个线程被cpu处理并执行
并行(cpu会轮询的执行线程)
线程的生命周期
java线程状态有六种,定义在Thread类的内部枚举类
public class Thread{
public enum State{
NEW,//新建
RUNNABLE.//可运行
BLOCKED,//上锁
WAITING,//无线等待
TIME_WAITING,//计时等待
TERMINATED;//被终止
}
}
网友评论