多线程02 线程创建

1、方式一:继承 Thread 类,重写run()方法,调用start()开启线程

public class Thread01 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName() + "正在执行" + i);
        }
    }
    // main() 是主线程
    public static void main(String[] args) throws InterruptedException {
        // 创建一个线程对象
        Thread01 thread = new Thread01();
        // 开启线程
        thread.start();
        // 主线程
        for (int i = 0; i < 500; i++) {
            System.out.println(Thread.currentThread().getName() + "正在执行" + i);
        }
    }
}

结果说明:开启的线程会在主线程中穿插输出结果,说明两个线程同时执行,先后顺序由CPU决定并调度

2、利用多线程下载网上图片案例

  • 引入 commons-io 依赖(我这里创建的是maven项目)
    <dependencies>
        <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
    </dependencies>
  • 编写代码
public class ThreadDemo01 extends Thread{
	// 文件url
    private String url;
    // 文件名
    private String name;
    public ThreadDemo01(String url,String name){
        this.url = url;
        this.name = name;
    }
    @Override
    public void run() {
        WebDownloader downloader = new WebDownloader();
        downloader.downloader(url,name);
        System.out.println("下载了图片" + name);
    }

    public static void main(String[] args) {
        String url = "https://timgsa.baidu.com/timg?image&amp;quality=80&amp;size=b9999_10000&amp;sec=1595174406474&amp;di=0bf83db78f86413f1016578681ff4366&amp;imgtype=0&amp;src=http%3A%2F%2Fimg.pconline.com.cn%2Fimages%2Fupload%2Fupc%2Ftx%2Fwallpaper%2F1304%2F17%2Fc5%2F19955421_1366189671581.jpg";
        String name = "1.jpg";
        String url1 = "https://timgsa.baidu.com/timg?image&amp;quality=80&amp;size=b9999_10000&amp;sec=1595174547720&amp;di=7ea8b3e68932fd1ea67733862e95b5f9&amp;imgtype=0&amp;src=http%3A%2F%2Fattachments.gfan.com%2Fforum%2F201604%2F23%2F002205xqdkj84gnw4oi85v.jpg";
        String name1 = "2.jpg";
        String url2 = "https://timgsa.baidu.com/timg?image&amp;quality=80&amp;size=b9999_10000&amp;sec=1595174659187&amp;di=28310821d7f0b02f0a063fbdc8a8a777&amp;imgtype=0&amp;src=http%3A%2F%2Fimg.pconline.com.cn%2Fimages%2Fupload%2Fupc%2Ftx%2Fwallpaper%2F1305%2F03%2Fc0%2F20496484_1367549048818.jpg";
        String name2 = "3.jpg";
        ThreadDemo01 t1 = new ThreadDemo01(url, name);
        ThreadDemo01 t2 = new ThreadDemo01(url1, name1);
        ThreadDemo01 t3 = new ThreadDemo01(url2, name2);
        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("下载文件出错 downloader()");
        }
    }
}

3、方式二:实现 Runnable 接口,重写run()方法,执行线程需要将 Runnable 接口实现类丢入Thread 对象中,调用start()开启线程

public class Thread02 implements Runnable{

    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName() + i);
        }
    }

    public static void main(String[] args) {
        // 创建 Runnable 实现类对象
        Thread02 runnable = new Thread02();
        // 创建thread对象,并将runnable实现类对象丢入构造器中
        Thread thread = new Thread(runnable);
        // 开启线程
        thread.start();

        for (int i = 0; i < 1000; i++) {
            System.out.println(Thread.currentThread().getName() + i);
        }
    }
}

4、小结
继承 Thread 类

  • 子类继承 Thread 类,具备多线程能力
  • 启动线程:子类对象.start()
  • 不建议使用:避免oop单继承的局限性

实现 Runnable 接口

  • 实现接口 Runnable ,具备多线程能力
  • 启动线程:Thread 对象构造器中传入 Runnable 实现类对象,Thread 对象.start()
  • 推荐使用:避免单继承的局限性,灵活方便,方便同一个对象被多个线程使用

5、利用多线程操作同一资源案例(初始并发问题)

public class ThreadDemo02 implements Runnable{

    private int tickets = 10;

    public void run() {
        while (true){
            if (tickets <= 0){
                break;
            }
            // 模拟耗时
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets-- + "张票!");
        }
    }

    public static void main(String[] args) {
        ThreadDemo02 ticket = new ThreadDemo02();
        new Thread(ticket,"张三").start();
        new Thread(ticket,"李四").start();
        new Thread(ticket,"王五").start();
    }
}

输出结果:出现并发问题!

李四正在出售第10张票!
张三正在出售第8张票!
王五正在出售第9张票!
张三正在出售第7张票!
李四正在出售第6张票!
王五正在出售第7张票!
王五正在出售第5张票!
李四正在出售第4张票!
张三正在出售第3张票!
李四正在出售第1张票!
王五正在出售第0张票!
张三正在出售第2张票!

6、龟兔赛跑案例

public class Race implements Runnable{

    private static String winner;

    public void run() {
        for (int i = 0; i <= 100; i++) {
            // 模拟兔子休息
            if (Thread.currentThread().getName().equals("兔子") && i%20==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 step){
        if (winner != null){
            return true;
        }
        if (step == 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();
    }
}

7、方式三:实现 Callable<> 接口,重写 call() 方法,利用线程池工具类创建线程池,调用submit()传入Callable对象开启线程,可以获取返回值

public class Thread03 implements Callable<Boolean> {
    // 文件url
    private String url;
    // 文件名
    private String name;

    public Thread03(String url, String name){
        this.url = url;
        this.name = name;
    }

    public Boolean call() throws Exception {
        WebDownloader2 downloader = new WebDownloader2();
        downloader.downloader(url,name);
        System.out.println("下载了图片" + name);
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        String url = "https://timgsa.baidu.com/timg?image&amp;quality=80&amp;size=b9999_10000&amp;sec=1595174406474&amp;di=0bf83db78f86413f1016578681ff4366&amp;imgtype=0&amp;src=http%3A%2F%2Fimg.pconline.com.cn%2Fimages%2Fupload%2Fupc%2Ftx%2Fwallpaper%2F1304%2F17%2Fc5%2F19955421_1366189671581.jpg";
        String name = "1.jpg";
        String url1 = "https://timgsa.baidu.com/timg?image&amp;quality=80&amp;size=b9999_10000&amp;sec=1595174547720&amp;di=7ea8b3e68932fd1ea67733862e95b5f9&amp;imgtype=0&amp;src=http%3A%2F%2Fattachments.gfan.com%2Fforum%2F201604%2F23%2F002205xqdkj84gnw4oi85v.jpg";
        String name1 = "2.jpg";
        String url2 = "https://timgsa.baidu.com/timg?image&amp;quality=80&amp;size=b9999_10000&amp;sec=1595174659187&amp;di=28310821d7f0b02f0a063fbdc8a8a777&amp;imgtype=0&amp;src=http%3A%2F%2Fimg.pconline.com.cn%2Fimages%2Fupload%2Fupc%2Ftx%2Fwallpaper%2F1305%2F03%2Fc0%2F20496484_1367549048818.jpg";
        String name2 = "3.jpg";
        Thread03 t1 = new Thread03(url,name);
        Thread03 t2 = new Thread03(url1,name1);
        Thread03 t3 = new Thread03(url2,name2);
        ExecutorService pool = Executors.newFixedThreadPool(1);
        Future<Boolean> r1 = pool.submit(t1);
        Future<Boolean> r2 = pool.submit(t2);
        Future<Boolean> r3 = pool.submit(t3);
        boolean o1 = r1.get();
        boolean o2 = r2.get();
        boolean o3 = r3.get();
        System.out.println(o1);
        System.out.println(o2);
        System.out.println(o3);
        // 关闭线程池
        pool.shutdown();
    }
}
// 下载器
class WebDownloader2{
    // 下载方法
    public void downloader(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("下载文件出错 downloader()");
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值