多线程一

多线程一

_

多任务

多任务.png

在现实生活中有太多这样同时做很多事情的例子了,看起来是很多任务同时做,其实本质上,我们的大脑在同一时间依旧只做了一件事。

多线程.png

原来是一条路,慢慢的因为车多了,道路阻塞,效率极低,为了提高使用效率,能够充分利用道路,于是加了多个车道,再也不用担心堵塞了。

普通方法调用和多线程

调用对比.png

程序-进程-线程

程序进程线程.png

Process与Thread

  • 程序是指令和数据的有序集合,其本身没有任何含义,是一个静态的概念。
  • 进程则是程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位。
  • 通常在一个进程中可以包含多个线程,一个进程至少包含一个线程。线程是CPU调度和执行的单位。

注意.png

核心概念

  • 线程就是独立的执行路径
  • 在程序运行时,即使没有自己创建线程,后台也会有很多线程,如主线程,Gc线程
  • main()称之为主线程,为系统的入口,用于执行整个程序
  • 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为干预的
  • 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制
  • 线程会带来额外的开销,如CPU调度时间,并发控制开销
  • 每个线程都在自己的工作内存交互,内存控制不当会造成数据不一致

线程的三种创建方式

线程创建方式.png

第一种->继承Thread

extengsThread.png# 继承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.png

/**
 * 第二种方式  实现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();
    }
}

模拟龟兔赛跑案例

龟兔赛跑.png

/**
 * 模拟龟兔赛跑
 */
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.png

使用 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();
    }

}

反射 2021-02-24
Lambda表达式 2021-02-26

评论区