一、概述
什么是多线程?
多线程是指多条路径同时进行,高效不用等待。
这里的同时是短暂执行不同时间片的任务,只是看似同时。很多多线程是模拟出来的,真正的多线程是指有多个CPU,即多核,如服务器。
如果是模拟出来的多线程,即一个CPU的情况下,在同一个时间点,CPU也只能执行一个代码,因为切换的很快,所有就有同时执行的错觉。
什么是三高?
- 高可用:数据不会出错
- 高性能:体验好,延时低
- 高并发:同时操作
多线程有什么特点?
1、方法间调用:普通方法调用,从哪里来到哪里去,闭合的一条路径。
2、多线程使用:开辟了多条路径。
- 程序:我们编写的代码
- 进程(Process):正在执行的程序
- 线程(Thread):进程中可以开辟多条路,每一条都是一个线程
每个线程都使用自己的工作内存,并且共同分享主存。
二、创建线程的三种方法
方法一:继承Thread类,重写run方法
1、创建:继承 Thread 类,重写 run() 方法
2、启动:创建子类对象,使用 start() 方法
1、实例:
public class StartThread extends Thread{
//线程入口点
public void run(){
for(int i=0;i<5;i++){
System.out.println("一边听歌");
}
}
public static void main(String[] args) {
//启动
StartThread thread = new StartThread();
thread.start(); //出现两条路径,不保证立即运行,由CPU调用
// thread.run(); //普通方法调用,没有实现多路径
for(int i=0;i<10;i++){
System.out.println("一边coding");
}
}
//多执行几次,每次结果都不一样
}
2、结果:
3、分析
StartThread thread = new StartThread(); 仅仅是创建了线程对象,需要调用 start() 开启线程,执行 run() 方法。总结如下:
- 执行线程必须调用start() 加入到调度器中
- 不一定立即执行,体统安排调度分配执行
- 直接调用 run() 不是开启多线程,只是普通方法的调用
虽然子类Thread具备了多线程的能力:
启动线程:子类对象.start()
但不建议使用:因为OOP具有单继承局限性
方法二:实现Runable接口,重写run方法
1、创建:实现Runnable,重写run() 方法
2、启动:创建实现类的对象+Thread对象+start() 方法
1、实例:
public class StartRun implements Runnable{
//线程入口点
public void run(){
for(int i=0;i<10;i++){
System.out.println("一边听歌");
}
}
public static void main(String[] args) {
//创建实现类的对象
StartRun sr = new StartRun();
//创建代理类的对象
Thread t = new Thread(sr);
//启动
t.start();
}
}
2、分析
- 实现接口 Runnable 具有多线程能力
- 启动线程:传入目标对象+Thread对象.start()
- 推荐使用:OOP多实现,灵活方便,便于对同一份对象的代理。且方便共享资源。
方法三:实现Callable接口,重写call方法
1、实例:
实现图片下载功能
public class CallDownloader implements Callable<Boolean>{
private String url; //远程路径
private String name; //存储名字
public CallDownloader(String url,String name){
this.url=url;
this.name=name;
System.out.println(name);
}
public static void main(String[] args) {
//1、创建目标对象:
CallDownloader cd1 =new CallDownloader("图片地址","baidu. png");
CallDownloader cd2 =new CallDownloader("图片地址","baidu. png");
CallDownloader cd3 =new CallDownloader("图片地址","baidu. png");
//2、创建执行服务:
ExecutorService ser = Executors.newFixedThreadPool(3);
//3、提交执行:
Future<Boolean> result1 = ser.submit(cd1);
Future<Boolean> result2 = ser.submit(cd2);
Future<Boolean> result3 = ser.submit(cd3);
//4、获取结果:
boolean r1 =result1.get();
boolean r2 =result2.get();
boolean r3 =result3.get();
System.out.println(r1+"--"+r2+"--"+r3);
//5、关闭服务:
ser. shutdownNow();
}
@Override
public Boolean call() throws Exception {
WebDownloader wd = new WebDownloader();
wd.download(url.name);
System.out.println(name);
return true;
}
}
2、分析:
- 可以throws出去异常,并且可以返回
- JUC并发包下,实现Callable接口
步骤:
<1>、创建目标对象
<2>、创建执行服务
<3>、提交执行
<4>、获取结果
<5>、关闭服务
三、总结
少用继承,多用实现(接口),因为单继承有局限性,继承一个类又需要继承许多其他类,需要重构代码。