多线程-线程创建的三种方式

线程的创建的三种方式

1.继承Thread类(重点)

实现方法:
  • 自定义线程类继承Thread
  • 重写**run()**方法,编写线程执行体
  • 创建线程对象,调用**start()**方法启动线程
//创建线程方式一:继承Thread类,重写run()方法,调用start开启线程
public class TestThread1 extends Thread{
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 200; i++) {
            System.out.println("我在看代码---" + i);
        }
    }

    public static void main(String[] args) {
        //创建一个线程对象
        TestThread1 testThread1 = new TestThread1();

        //调用start方法开启线程
        testThread1.start();

        for (int i = 0; i < 200; i++) {
            System.out.println("我在学习多线程---" + i);
        }
    }
}

总结:注意,线程开启不一定立即执行,由cpu调度执行

不建议使用:避免OOP单继承的局限性

多线程同步下载图片

需求:练习Thread,实现多线程同步下载图片

  • 将commons.io包下载并导入lib目录

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yzSJQpc5-1628670582068)(C:\Users\zhou\AppData\Roaming\Typora\typora-user-images\image-20210810161719664.png)]

  • 编写下载器

    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方法出现问题");
            }
        }
    }
    
  • 编写下载图片线程run()方法的执行体

    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);
    }
    

调用start()启动线程

public static void main(String[] args) {
    TestThread2 t1 = new TestThread2("https://img2.baidu.com/it/u=2379421903,2766120725&fm=26&fmt=auto&gp=0.jpg", "1.jpg");
    TestThread2 t2 = new TestThread2("https://img0.baidu.com/it/u=2580887492,2953392680&fm=26&fmt=auto&gp=0.jpg", "2.jpg");
    TestThread2 t3 = new TestThread2("https://img2.baidu.com/it/u=3562631285,4033075858&fm=26&fmt=auto&gp=0.jpg", "3.jpg");

    //先下载t1
    t1.start();
    //然后是t2
    t2.start();
    //最后是t3
    t3.start();
}

执行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B5EY6nuD-1628670582069)(C:\Users\zhou\AppData\Roaming\Typora\typora-user-images\image-20210810163317143.png)]

查看文件,已经存在1.jpg, 2.jpg, 3.jpg

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7R3SyQiv-1628670582070)(C:\Users\zhou\AppData\Roaming\Typora\typora-user-images\image-20210810163349613.png)]

2.实现Runnable接口(重点)

实现方法:
  • 定义MyRunnable类实现Runnable接口
  • 实现run()方法,编写线程执行体
  • 创建线程对象,调用start()方法启动线程
//创建线程方式2:实现runnable接口,重写run方法,执行线程需要丢人runnable接口实现类,调用start方法
public class TestThread3 implements Runnable{

    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 200; i++) {
            System.out.println("我在看代码---" + i);
        }
    }

    public static void main(String[] args) {
        //创建runnable接口的实现类对象
        TestThread3 testThread3 = new TestThread3();

        //创建线程对象,通过线程对象来开启线程
        //Thread thread = new Thread(testThread3);

        //thread.start();

        new Thread(testThread3).start();

        for (int i = 0; i < 200; i++) {
            System.out.println("我在学习多线程---" + i);
        }
    }
}

总结:推荐使用,避免单继承局限性,灵活方便,方便同一个对象被多个线程使用

并发问题初识—火车抢票案例

火车票抢票问题:

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 ticket = new TestThread4();

        new Thread(ticket, "小明").start();
        new Thread(ticket, "老师").start();
        new Thread(ticket, "黄牛党").start();
    }
}

发现问题:当多个资源操作同一个资源的情况下,线程不安全,数据紊乱

龟兔赛跑案例-Race
//模拟龟兔赛跑
public class Race implements Runnable{

    //胜利者
    private static 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 + "步");
        }
    }

    //判断是否完成比赛
    private 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();
    }
}

输出结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qExHuyFs-1628670582071)(C:\Users\zhou\AppData\Roaming\Typora\typora-user-images\image-20210810171301805.png)]

3.实现Callable接口(了解)

  1. 实现Callable接口,需要返回值类型

  2. 重写call方法,需要抛出异常

  3. 创建目标对象

  4. 创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(3);

  5. 提交执行:Future r1 = ser.submit(t1);

  6. 获取结果:boolean rs1 = r1.get();

  7. 关闭服务:ser.shutdownNow();

    演示:用Callable改造下载图片案例

    import org.apache.commons.io.FileUtils;
    
    import java.io.File;
    import java.io.IOException;
    import java.net.URL;
    import java.util.concurrent.*;
    
    //线程创建方式三:实现Callable接口
    /*
        callable的好处:
        1.可以自定义返回值
        2.可以抛出异常
     */
    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() {
            WebDownLoader webDownLoader = new 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=2379421903,2766120725&fm=26&fmt=auto&gp=0.jpg", "1.jpg");
            TestCallable t2 = new TestCallable("https://img0.baidu.com/it/u=2580887492,2953392680&fm=26&fmt=auto&gp=0.jpg", "2.jpg");
            TestCallable t3 = new TestCallable("https://img2.baidu.com/it/u=3562631285,4033075858&fm=26&fmt=auto&gp=0.jpg", "3.jpg");
    
            //创建执行服务:
            ExecutorService ser = Executors.newFixedThreadPool(3);
    
            //提交执行
            Future<Boolean> r1 = ser.submit(t1);
            Future<Boolean> r2 = ser.submit(t2);
            Future<Boolean> r3 = ser.submit(t3);
    
            //获取结果
            boolean rs1 = r1.get();
            boolean rs2 = r2.get();
            boolean rs3 = r3.get();
    
            System.out.println(rs1);
            System.out.println(rs2);
            System.out.println(rs3);
    
            //关闭服务
            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方法出现问题");
            }
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值