多任务
![]()
在现实生活中有太多这样同时做很多事情的例子了,看起来是很多任务同时做,其实本质上,我们的大脑在同一时间依旧只做了一件事。
![]()
原来是一条路,慢慢的因为车多了,道路阻塞,效率极低,为了提高使用效率,能够充分利用道路,于是加了多个车道,再也不用担心堵塞了。
普通方法调用和多线程
![]()
程序-进程-线程
![]()
Process与Thread
- 程序是指令和数据的有序集合,其本身没有任何含义,是一个静态的概念。
- 进程则是程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位。
- 通常在一个进程中可以包含多个线程,一个进程至少包含一个线程。线程是CPU调度和执行的单位。
![]()
核心概念
- 线程就是独立的执行路径
- 在程序运行时,即使没有自己创建线程,后台也会有很多线程,如主线程,Gc线程
- main()称之为主线程,为系统的入口,用于执行整个程序
- 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为干预的
- 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制
- 线程会带来额外的开销,如CPU调度时间,并发控制开销
- 每个线程都在自己的工作内存交互,内存控制不当会造成数据不一致
线程的三种创建方式
![]()
第一种->继承Thread
# 继承Thread类
练习
网络图片下载
**
* 练习Thread 多线程下载网络图片
*/
public class WebDownloader {
/**传入一个 图片的url和图片存放的位置*/
public void downloader(String url,String file){
try {
URL u = new URL(url);
URLConnection urlConnection = u.openConnection();
InputStream in = urlConnection.getInputStream();
//创建一个输出流
FileOutputStream fos = new FileOutputStream(file);
//创建一个缓冲数组
byte [] b = new byte[1024];
int len;
while((len = in.read(b))!=-1){
fos.write(b,0,len);
}
//关流
fos.close();
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Test extends Thread{
//图片地址
private String url;
//图片存放路径
private String file;
public Test(String url, String file) {
this.url = url;
this.file = file;
}
//重写run方法
@Override
public void run(){
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url,file);
System.out.println("文件"+file+"下载完毕了");
}
public static void main(String[] args) {
Test t1 = new Test("http://c.qicong77.com/halo/preview_1610719918207.jpg","1.jpg");
Test t2 = new Test("http://c.qicong77.com/halo/preview_1610308888540.jpg","2.jpg");
Test t3 = new Test("http://c.qicong77.com/halo/preview_1610451362652.jpg","3.jpg");
//开启线程
t1.start();
t2.start();
t3.start();
}
}
第二种-> 实现Runnable接口
![]()
/**
* 第二种方式 实现Runnable接口
*/
public class TestRunnable implements Runnable {
@Override
public void run() {
System.out.println("实现Runnable接口");
}
}
class Test{
public static void main(String[] args) {
//创建TestRunnable 对象
TestRunnable tr = new TestRunnable();
//创建代理对象并启动
new Thread(tr).start();
}
}
模拟抢票案例
//模拟抢票
public class RobTicket implements Runnable{
//有十张票
private int ticket = 10;
@Override
public void run() {
while (true){
//当票数为0时跳出循环
if (ticket<=0){
break;
}
System.out.println(Thread.currentThread().getName()+"抢到了第"+ticket--+"张票");
//休眠一下
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Test4{
public static void main(String[] args) {
RobTicket rt = new RobTicket();
new Thread(rt,"小明").start();
new Thread(rt,"小白").start();
new Thread(rt,"黄牛").start();
}
}
模拟龟兔赛跑案例
![]()
/**
* 模拟龟兔赛跑
*/
public class Race implements Runnable {
//胜利者
private static String winner = null;
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
Boolean flag = victory(i);
//如果等于true 说明有了胜利者 结束循环。
if (flag){
break;
}
//兔子中途会睡觉
if("兔子".equals(Thread.currentThread().getName())&&i-50==0){
try {
Thread.sleep(1);
System.out.println(Thread.currentThread().getName()+"休眠了");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
}
}
//判定比赛胜利
public Boolean victory(int stepNumber){
//先判定有没有胜利者 有就返回true
if (winner!=null){
return true;
//判定谁先到达100步
}else if (stepNumber>=100){
winner = Thread.currentThread().getName();
System.out.println(winner+"获得了胜利");
return true;
}else {
//都没有达到,返回false 继续跑
return false;
}
}
public static void main(String[] args) {
Race r = new Race();
new Thread(r,"兔子").start();
new Thread(r,"乌龟").start();
}
}
第三种->实现Callbale接口
![]()
使用 Callable 实现图片下载
封装下载类
public class ImgDownloader {
public static void downloader(String url,String file) throws IOException {
URL u = new URL(url);
URLConnection urlConnection = u.openConnection();
//获得流对象
InputStream inputStream = urlConnection.getInputStream();
//创建输出流
FileOutputStream fos = new FileOutputStream(file);
//缓存数组
byte [] b = new byte[1024];
//一次读取的字节
int len;
while ((len=inputStream.read(b))!=-1){
//将一次读取到缓存数组的数据全部写入file
fos.write(b,0,len);
}
System.out.println("文件: "+file+" 下载完毕了");
//关流
inputStream.close();
fos.close();
}
}
使用Callbale执行下载
public class TestCallable implements Callable<Boolean> {
private String url;
private String file;
public TestCallable(String url, String file) {
this.url = url;
this.file = file;
}
@Override
public Boolean call() throws Exception {
ImgDownloader.downloader(url,file);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestCallable t1 = new TestCallable("http://c.qicong77.com/halo/preview_1610719918207.jpg","1.jpg");
TestCallable t2 = new TestCallable("http://c.qicong77.com/halo/preview_1610308888540.jpg","2.jpg");
TestCallable t3 = new TestCallable("http://c.qicong77.com/halo/preview_1610451362652.jpg","3.jpg");
//创建执行服务
ExecutorService executorService = Executors.newFixedThreadPool(3);
//提交执行
Future<Boolean> submit1 = executorService.submit(t1);
Future<Boolean> submit2 = executorService.submit(t2);
Future<Boolean> submit3 = executorService.submit(t3);
//获取结果
Boolean aBoolean1 = submit1.get();
Boolean aBoolean2 = submit2.get();
Boolean aBoolean3 = submit3.get();
System.out.println(aBoolean1);
System.out.println(aBoolean2);
System.out.println(aBoolean3);
//关闭服务
executorService.shutdownNow();
}
}