学习笔记-线程简介及线程的三种创建方式

学习来源: B站【狂神说Java】多线程详解

线程简介

  • 多任务:同时交替做几件事
  • 多线程:堵车,增加车道

普通方法调用和多线程

Process与Thread

  • 程序:是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念
  • 进程:是执行程序的一次执行过程,是一个动态的概念。是系统资源分配的单位
  • 通常一个进程中可以包含若干个线程,当然一个进程中至少又一个线程,不然没有存在的意义。线程是CPU调度和执行的单位
  • 注意:很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核,如服务器。如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点,在同一个时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错觉。

线程的创建

三种创建方式

  • Thread class

    • 自定义线程类继承Thread类

    • 重写run()方法,编写线程执行体

    • 创建线程对象,调用start()方法启动线程

      package com.xxx.demo01;
      
      //创建线程方式1:继承Thread类,重写run()方法,调用start开启线程
      //总结:注意,线程开启不一定立即执行,由cpu调度安排执行
      public class ThreadTest extends Thread{
          @Override
          public void run() {
              for (int i = 0; i < 200; i++) {
                  System.out.println("我在看代码----"+i);
              }
          }
      
          public static void main(String[] args) {
              //main线程,主线程
              //创建一个线程对象
              ThreadTest threadTest = new ThreadTest();
              //threadTest.run();无法实现多线程,按顺序执行
      
              //调用start方法开启线程
              threadTest.start();
              for (int i = 0; i < 3000; i++) {
                  System.out.println("我在学习多线程----"+i);
              }
      
          }
      }
      
      
    • 网图下载

      package com.xxx.demo01;
      
      import org.apache.commons.io.FileUtils;
      
      import java.io.File;
      import java.io.IOException;
      import java.net.URL;
      
      //练习Thread,实现多线程同步下载图片
      public class TestThread2 extends Thread{
          private String url; //网络图片地址
          private String name; //保存的文件名
          public TestThread2(String url,String name){
              this.url = url;
              this.name = name;
          }
      
          @Override
          public void run() {
              WebDownloader webDownloader = new WebDownloader();
              webDownloader.downloader(url,name);
              System.out.println("下载了文件名为:"+name);
          }
      
          public static void main(String[] args) {
              TestThread2 t1 = new TestThread2("https://img2.baidu.com/it/u=1413145394,2503085832&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=313","萌宠1.jpg");
              TestThread2 t2 = new TestThread2("https://img0.baidu.com/it/u=767677655,2564277568&fm=253&fmt=auto&app=138&f=JPEG?w=870&h=419","萌宠2.jpg");
              TestThread2 t3 = new TestThread2("https://img1.baidu.com/it/u=4218385766,4246941889&fm=253&fmt=auto&app=138&f=JPEG?w=400&h=600","萌宠3.jpg");
      
              t1.start();
              t2.start();
              t3.start();
      
          }
      }
      //下载器
      class WebDownloader{
          public void downloader(String url,String name){
              try {
                  FileUtils.copyURLToFile(new URL(url),new File(name));
              } catch (IOException e) {
                  e.printStackTrace();
                  System.out.println("IO异常,downloader方法出现问题");
              }
          }
      }
      
      
  • Runnable 接口

    • 定义MyRunnable类实现Runnable接口
    • 实现run()方法,编写线程执行体
    • 创建线程对象,调用start()方法启动线程
    package com.xxx.demo01;
    
    //创建线程方式2:实现runnable接口,重新run方法,执行线程需要丢入runnable接口实现类,调用start方法
    public class TestThread3 implements Runnable{
        @Override
        public void run() {
            for (int i = 0; i < 200; i++) {
                System.out.println("我在看代码----"+i);
            }
        }
    
        public static void main(String[] args) {
            TestThread3 testThread3 = new TestThread3();
            //Thread thread = new Thread(testThread3);
            //thread.start();
    
            new Thread(testThread3).start();
            for (int i = 0; i < 3000; i++) {
                System.out.println("我在学习多线程----"+i);
            }
    
        }
    }
    
    package com.xxx.demo01;
    
    import org.apache.commons.io.FileUtils;
    
    import java.io.File;
    import java.io.IOException;
    import java.net.URL;
    
    //练习Thread,实现多线程同步下载图片
    public class TestThread2 implements Runnable{
        private String url; //网络图片地址
        private String name; //保存的文件名
        public TestThread2(String url,String name){
            this.url = url;
            this.name = name;
        }
    
        @Override
        public void run() {
            WebDownloader webDownloader = new WebDownloader();
            webDownloader.downloader(url,name);
            System.out.println("下载了文件名为:"+name);
        }
    
        public static void main(String[] args) {
            TestThread2 t1 = new TestThread2("https://img2.baidu.com/it/u=1413145394,2503085832&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=313","萌宠1.jpg");
            TestThread2 t2 = new TestThread2("https://img0.baidu.com/it/u=767677655,2564277568&fm=253&fmt=auto&app=138&f=JPEG?w=870&h=419","萌宠2.jpg");
            TestThread2 t3 = new TestThread2("https://img1.baidu.com/it/u=4218385766,4246941889&fm=253&fmt=auto&app=138&f=JPEG?w=400&h=600","萌宠3.jpg");
    
            new Thread(t1).start();
            new Thread(t2).start();
            new Thread(t3).start();
    
        }
    }
    
    //下载器
    class WebDownloader{
        public void downloader(String url,String name){
            try {
                FileUtils.copyURLToFile(new URL(url),new File(name));
            } catch (IOException e) {
                e.printStackTrace();
                System.out.println("IO异常,downloader方法出现问题");
            }
        }
    }
    
  • 小结

    • 继承Thread类
      • 子类继承Thread类具备多线程能力
      • 启动线程:子类对象.start()
      • 不建议使用:避免OOP单继承局限性
    • 实现Runable接口
      • 实现接口Runnable具有多线程能力
      • 启动线程:传入目标对象+Thread对象.start()
      • 推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
  • 初识并发问题

package com.xxx.demo01;

//多个线程同时操作一个对象
//买火车票的例子

//发现问题:多个线程操作同一个资源的情况下,线程不安全,数据紊乱
public class TestThread4 implements Runnable{
    private int ticketNums = 10;
    @Override
    public void run() {
        while(true){
            if(ticketNums < 0){
                break;
            }
            //模拟延时
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"---->拿到了第"+ ticketNums-- + "张票");
        }
    }

    public static void main(String[] args) {
        TestThread4 testThread4 = new TestThread4();
        new Thread(testThread4,"小明").start();
        new Thread(testThread4,"老师").start();
        new Thread(testThread4,"黄牛党").start();
    }
}

  • 案例:龟兔赛跑-Race
    1. 首先来个赛道距离,然后要离终点越来越近
    2. 判断比赛是否结束
    3. 打印出胜利者
    4. 龟兔赛跑开始
    5. 故事中是乌龟赢的,兔子需要睡觉,所以需要模拟兔子睡觉
    6. 最终,乌龟赢得比赛
package com.xxx.demo01;

//模拟龟兔赛跑
public class Race implements Runnable{
    private String winner;
    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {

            if(Thread.currentThread().getName().equals("兔子") & i % 10 == 0){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            boolean flag = gameOver(i);
            //如果比赛结束,就停止程序
            if(flag){
                break;
            }
            System.out.println(Thread.currentThread().getName() + "跑了" + i +"步");

        }
    }
    //判断是否完成比赛
    public boolean gameOver(int steps){
        if(winner != null){
            return true;
        }{
            if(steps == 100){
                winner = Thread.currentThread().getName();
                System.out.println("winner is" + winner);
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        Race race = new Race();
        new Thread(race,"兔子").start();
        new Thread(race,"乌龟").start();
    }
}

  • 实现Callable接口

    1. 实现Callable接口,需要返回值类型
    2. 重写call方法,需要抛出异常
    3. 创建目标对象
    4. 创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
    5. 提交执行:Future result1 = ser.submit(t1);
    6. 获取结果:boolean r1 = result1.get();
    7. 关闭服务:ser.shutdownNow();
    //利用callable改造下载图片案例
    package com.xxx.demo02;
    
    import org.apache.commons.io.FileUtils;
    
    import java.io.File;
    import java.io.IOException;
    import java.net.URL;
    import java.util.concurrent.*;
    
    //线程创建三:实现Callable接口
    public class TestCallable implements Callable<Boolean> {
        private String url; //网络图片地址
        private String name; //保存的文件名
        public TestCallable(String url,String name){
            this.url = url;
            this.name = name;
        }
    
        @Override
        public Boolean call() {
            com.xxx.demo02.WebDownloader webDownloader = new com.xxx.demo02.WebDownloader();
            webDownloader.downloader(url,name);
            System.out.println("下载了文件名为:"+name);
            return true;
        }
    
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            TestCallable t1 = new TestCallable("https://img2.baidu.com/it/u=1413145394,2503085832&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=313","萌宠1.jpg");
            TestCallable t2 = new TestCallable("https://img0.baidu.com/it/u=767677655,2564277568&fm=253&fmt=auto&app=138&f=JPEG?w=870&h=419","萌宠2.jpg");
            TestCallable t3 = new TestCallable("https://img1.baidu.com/it/u=4218385766,4246941889&fm=253&fmt=auto&app=138&f=JPEG?w=400&h=600","萌宠3.jpg");
            //1. 创建执行服务:
            ExecutorService ser = Executors.newFixedThreadPool(3);
            //2. 提交执行:
            Future<Boolean> result1 = ser.submit(t1);
            Future<Boolean> result2 = ser.submit(t2);
            Future<Boolean> result3 = ser.submit(t3);
            //3. 获取结果:
            boolean r1 = result1.get();
            boolean r2 = result1.get();
            boolean r3 = result1.get();
            //4. 关闭服务:
            ser.shutdownNow();
    
    
        }
    
    }
    
    //下载器
    class WebDownloader{
        public void downloader(String url,String name){
            try {
                FileUtils.copyURLToFile(new URL(url),new File(name));
            } catch (IOException e) {
                e.printStackTrace();
                System.out.println("IO异常,downloader方法出现问题");
            }
        }
    }
    
    

posted @ 2022-07-28 22:19  夏夜晚风-  阅读(54)  评论(0编辑  收藏  举报