美文网首页IT@程序员猿媛SpringBoot精选
还不理解多线程,几个demo来搞定

还不理解多线程,几个demo来搞定

作者: 程就人生 | 来源:发表于2019-11-12 22:24 被阅读0次
图片来自网络

本文主要整理了关于多线程的五个demo,以demo来说明Java中多线程的演进之路,写法上是如何从繁到简的,这样更易于理解复杂场景下的多线程。

第一个demo
说到Java中的多线程,小伙伴们肯定想到了Thread类和Runnable接口,要实现多线程,可以继承Thread类,也可以实现Runnable接口;打开Thread类的源码,可以发现Thread类本身就是实现Runnable接口的。

现在写两个类,分别演示一下多线程。第一个类实现了Runnable接口:

/**
 * 通过实现Runnable接口实现多线程
 * @author 程就人生
 * @date 2019年11月11日
 */
public class DemoByRunable implements Runnable{
    
    private int i;  
    DemoByRunable(int i){
        this.i = i;
    }

    @Override
    public void run() {
        System.out.println("当前第" + i + "个线程;");
    }

    /**
     * 测试
     * @param argo
     *
     */
    public static void main(String[] argo){
        DemoByRunable demo;     
        for(int i=0;i<10;i++){
            demo = new DemoByRunable(i+1);
            demo.run();
        }       
    }
}

运行结果如下:

当前第1个线程;
当前第2个线程;
当前第3个线程;
当前第4个线程;
当前第5个线程;
当前第6个线程;
当前第7个线程;
当前第8个线程;
当前第9个线程;
当前第10个线程;

第二个类继承了Thread类:

/**
 * 通过继承Thread类实现多线程
 * @author 程就人生
 * @date 2019年11月11日
 */
public class DemoByThread extends Thread{

    private int i;
    
    DemoByThread(int i){
        this.i = i;
    }
    
    public void run() {  
        System.out.println("当前第" + i + "个线程;");
    }  
    
    public static void main(String[] argo){
        DemoByThread demo;      
        for(int i=0;i<10;i++){
            demo = new DemoByThread(i+1);
            demo.start();
        }
        
    }
}

运行结果如下:

当前第2个线程;
当前第6个线程;
当前第5个线程;
当前第4个线程;
当前第1个线程;
当前第8个线程;
当前第9个线程;
当前第3个线程;
当前第10个线程;
当前第7个线程;

从执行结果来看,实现接口的是按照顺序来的,继承类的是无序的。

很多时候,我们需要做的事情,是有分工的,一个线程就相当于一个分工,当几个线程都完成后,任务才能走完最后一步。其中的一个线程没有走完,其他的线程则需要等待。就拿最经典、最易懂的泡茶,来看看多线程的实现吧。

第二个demo

/**
 * 
 * @author 程就人生
 * @date 2019年11月11日
 */
public class JoinDemo {
    //假设用时
    public static final int SLEEP_GAP = 500;

    //获取线程名称
    public static String getCurThreadName() {
        return Thread.currentThread().getName();
    }
    //烧热水的线程
    static class HeatUpWarterThread extends Thread {

        public HeatUpWarterThread() {
            super("烧水-Thread");
            System.out.println("烧水线程开始运行.....");
        }

        public void run() {
            try {
                System.out.println("洗好水壶");
                System.out.println("灌上凉水");
                System.out.println("放在火上");
                //线程睡眠一段时间,代表烧水中
                Thread.sleep(SLEEP_GAP);
                System.out.println("水开了.....");

            } catch (InterruptedException e) {
                System.out.println(" 发生异常被中断.");
            }
            System.out.println("烧水线程,运行结束.");
        }

    }
    //清洗的线程
    static class WashThread extends Thread {

        public WashThread() {
            super("清洗-Thread");
            System.out.println("清洗线程开始运行.....");
        }

        public void run() {

            try {
                System.out.println("洗茶壶");
                System.out.println("洗茶杯");
                System.out.println("拿茶叶");
                //线程睡眠一段时间,代表清洗中
                Thread.sleep(SLEEP_GAP);
                System.out.println("洗完了......");

            } catch (InterruptedException e) {
                System.out.println(" 发生异常被中断.");
            }
            System.out.println("清洗线程,运行结束.");
        }

    }

    //主线程
    public static void main(String args[]) {

        Thread hThread = new HeatUpWarterThread();
        Thread wThread = new WashThread();

        hThread.start();
        wThread.start();
        try {
            // 合并烧水-线程
            hThread.join();
            // 合并清洗-线程
            wThread.join();

            Thread.currentThread().setName("主线程");
            System.out.println("泡茶喝");

        } catch (InterruptedException e) {
            System.out.println(getCurThreadName() + "发生异常被中断.");
        }
        System.out.println(getCurThreadName() + " 运行结束.");
    }
}

执行结果

烧水线程开始运行.....
清洗线程开始运行.....
洗好水壶
灌上凉水
放在火上
洗茶壶
洗茶杯
拿茶叶
洗完了......
清洗线程,运行结束.
水开了.....
烧水线程,运行结束.
泡茶喝
主线程 运行结束.

上面的代码,继承了thread类实现的多线程,哪个线程先完成还是后完成,都是随机的。两个线程的运行,需要相互的等,等都完成了,才能最终泡茶喝。每个线程的执行结果是无法获取到的,这是潜在的问题。

第三个demo
在Java1.5版本之后,添加了新的类FutureTask,位于java.util.concurrent包中,先看看如何实现,有没有什么改进之处。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * JavaFutureTask多线程演示示例
 * @author 程就人生
 * @date 2019年11月12日
 */
public class JavaFutureDemo {

    //耗時
    public static final int SLEEP_GAP = 500;

    public static String getCurThreadName() {
        return Thread.currentThread().getName();
    }

    static class HeatUpWarterThread implements Callable<Boolean>{

        @Override
        public Boolean call() throws Exception{
            System.out.println("准备开始烧水的工作.....");
            try {
                System.out.println("洗好水壶");
                System.out.println("灌上凉水");
                System.out.println("放在火上");

                // 线程睡眠一段时间,代表烧水中
                Thread.sleep(SLEEP_GAP);
                System.out.println("水开了");

            } catch (InterruptedException e) {
                System.out.println(" 发生异常被中断.");
                return false;
            }
            System.out.println("烧水工作,运行结束.");
            return true;
        }
    }

    static class WashJob implements Callable<Boolean> {
        @Override
        public Boolean call() throws Exception {
            System.out.println("准备开始清洗的工作.....");
            try {
                System.out.println("洗茶壶");
                System.out.println("洗茶杯");
                System.out.println("拿茶叶");
                // 线程睡眠一段时间,代表清洗中
                Thread.sleep(SLEEP_GAP);
                System.out.println("洗完了");

            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("清洗工作,发生异常被中断.");
                return false;
            }
            System.out.println("清洗工作,运行结束.");
            return true;
        }
    }
    
    //主綫程
    public static void main(String args[]) {
        //構造燒水的线程
        Callable<Boolean> hJob = new HeatUpWarterThread();
        FutureTask<Boolean> hTask = new FutureTask<>(hJob);
        Thread hThread = new Thread(hTask, "烧水-Thread");

        //构造清洗的线程
        Callable<Boolean> wJob = new WashJob();
        FutureTask<Boolean> wTask = new FutureTask<>(wJob);
        Thread wThread = new Thread(wTask, "清洗-Thread");
        
        //开始工作
        hThread.start();
        wThread.start();        
        Thread.currentThread().setName("主线程");
        try {
            //返回烧水的结果
            boolean hOk = hTask.get();
            //返回清洗的结果
            boolean wOk = wTask.get();
            if (hOk && wOk) {
                System.out.println("泡茶喝");
            } else if (!hOk) {
                System.out.println("烧水失败,没有茶喝了");
            } else if (!wOk) {
                System.out.println("杯子洗不了,没有茶喝了");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println(getCurThreadName() + "发生异常被中断.");
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println(getCurThreadName() + " 运行结束.");
    }
}

运行结果:

准备开始烧水的工作.....
洗好水壶
灌上凉水
放在火上
准备开始清洗的工作.....
洗茶壶
洗茶杯
拿茶叶
水开了
烧水工作,运行结束.
洗完了
清洗工作,运行结束.
泡茶喝
主线程 运行结束.

通过实现Callable接口,在通过FutureTask,就可以获得每个线程的执行结果了,似乎方便了不少。还有更好用一点的,下面看一看google的Guava吧。

第四个demo

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;

/**
 * 使用google的Guava( 17.0版本) 演示多線程示例
 * @author 程就人生
 * @date 2019年11月12日
 */
public class GuavaFutureDemo {

    public static final int SLEEP_GAP = 500;


    public static String getCurThreadName() {
        return Thread.currentThread().getName();
    }
    //燒水線程
    static class HotWarterJob implements Callable<Boolean>{

        @Override
        public Boolean call() throws Exception{
            System.out.println("准备开始烧水的工作.....");
            try {
                System.out.println("洗好水壶");
                System.out.println("灌上凉水");
                System.out.println("放在火上");

                //线程睡眠一段时间,代表烧水中
                Thread.sleep(SLEEP_GAP);
                System.out.println("水开了");

            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("发生异常被中断.");
                return false;
            }
            System.out.println("烧水工作,运行结束.");

            return true;
        }
    }
    //清洗線程
    static class WashJob implements Callable<Boolean> {

        @Override
        public Boolean call() throws Exception {
            System.out.println("准备开始清洗的工作.....");
            try {
                System.out.println("洗茶壶");
                System.out.println("洗茶杯");
                System.out.println("拿茶叶");
                //线程睡眠一段时间,代表清洗中
                Thread.sleep(SLEEP_GAP);
                System.out.println("洗完了");

            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println(" 清洗工作 发生异常被中断.");
                return false;
            }
            System.out.println("清洗工作,运行结束.");
            return true;
        }

    }
    //泡茶线程,最後要執行的線程,掌握前兩個線程的執行結果
    static class MainJob implements Runnable {

        boolean warterOk = false;
        boolean cupOk = false;
        int gap = SLEEP_GAP / 10;

        @Override
        public void run() {
            while (true) {
                try {
                    Thread.sleep(gap);
                    System.out.println("閒來無事,读书中......");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.out.println(getCurThreadName() + "发生异常被中断.");
                }

                if (warterOk && cupOk) {
                    drinkTea(warterOk, cupOk);
                }
            }
        }

        public void drinkTea(Boolean wOk, Boolean cOK) {
            if (wOk && cOK) {
                System.out.println("泡茶喝,茶喝完");
                this.warterOk = false;
                this.gap = SLEEP_GAP * 100;
            } else if (!wOk) {
                System.out.println("烧水失败,没有茶喝了");
            } else if (!cOK) {
                System.out.println("杯子洗不了,没有茶喝了");
            }

        }
    }

    public static void main(String args[]) {

        //新起一个线程,作为泡茶主线程
        MainJob mainJob = new MainJob();
        Thread mainThread = new Thread(mainJob);
        mainThread.setName("主线程");
        mainThread.start();

        //烧水的业务逻辑
        Callable<Boolean> hotJob = new HotWarterJob();
        //清洗的业务逻辑
        Callable<Boolean> washJob = new WashJob();

        //创建java 线程池
        ExecutorService jPool = Executors.newFixedThreadPool(10);

        //包装java线程池,构造guava 线程池
        ListeningExecutorService gPool = MoreExecutors.listeningDecorator(jPool);

        //提交烧水的业务逻辑,取到异步任务
        ListenableFuture<Boolean> hotFuture = gPool.submit(hotJob);
        //绑定任务执行完成后的回调,到异步任务
        Futures.addCallback(hotFuture, new FutureCallback<Boolean>() {
            public void onSuccess(Boolean r) {
                if (r) {
                    mainJob.warterOk = true;
                }
            }
            //失敗的處理
            public void onFailure(Throwable t) {
                System.out.println("烧水失败,没有茶喝了");
            }
        });
        
        //提交清洗的业务逻辑,取到异步任务
        ListenableFuture<Boolean> washFuture = gPool.submit(washJob);
        //绑定任务执行完成后的回调,到异步任务
        Futures.addCallback(washFuture, new FutureCallback<Boolean>() {
            public void onSuccess(Boolean r) {
                if (r) {
                    mainJob.cupOk = true;
                }
            }
            //失敗的處理
            public void onFailure(Throwable t) {
                System.out.println("杯子洗不了,没有茶喝了");
            }
        });
    }
}

来看看执行的结果:

准备开始烧水的工作.....
洗好水壶
灌上凉水
放在火上
閒來無事,读书中......
准备开始清洗的工作.....
洗茶壶
洗茶杯
拿茶叶
閒來無事,读书中......
閒來無事,读书中......
閒來無事,读书中......
閒來無事,读书中......
閒來無事,读书中......
閒來無事,读书中......
閒來無事,读书中......
閒來無事,读书中......
閒來無事,读书中......
水开了
烧水工作,运行结束.
洗完了
清洗工作,运行结束.
閒來無事,读书中......
泡茶喝,茶喝完
閒來無事,读书中......

在这个demo中,需要引入Guava的架包,版本还不能太高,这是值得注意的。

<dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>17.0</version>
        </dependency>

第五个demo
最后一个,压轴大戏,如何把泡茶的多线程写的再简单、简洁易懂些,下面来看看。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * 线程池的使用示例
 * @author 程就人生
 * @date 2019年11月12日
 */
public class JavaFuturePoolDemo {

    public static final int SLEEP_GAP = 500;


    public static String getCurThreadName() {
        return Thread.currentThread().getName();
    }
    //烧水线程
    static class HotWarterJob implements Callable<Boolean>  {

        @Override
        public Boolean call() throws Exception {
            System.out.println("准备开始烧水的工作.....");
            try {
                System.out.println("洗好水壶");
                System.out.println("灌上凉水");
                System.out.println("放在火上");

                //线程睡眠一段时间,代表烧水中
                Thread.sleep(SLEEP_GAP);
                System.out.println("水开了.......");

            } catch (InterruptedException e) {
                System.out.println(" 发生异常被中断.");
                return false;
            }
            System.out.println(" 运行结束.");

            return true;
        }
    }
    //清洗线程
    static class WashJob implements Callable<Boolean> {

        @Override
        public Boolean call() throws Exception {
            System.out.println("准备开始清洗的工作.....");
            try {
                System.out.println("洗茶壶");
                System.out.println("洗茶杯");
                System.out.println("拿茶叶");
                //线程睡眠一段时间,代表清洗中
                Thread.sleep(SLEEP_GAP);
                System.out.println("洗完了..........");

            } catch (InterruptedException e) {
                System.out.println("清洗工作,发生异常被中断.");
                return false;
            }
            System.out.println("清洗工作,运行结束.");
            return true;
        }

    }


    public static void main(String args[]) {

        Callable<Boolean> hJob = new HotWarterJob();//异步逻辑

        Callable<Boolean> wJob = new WashJob();//异步逻辑

        ExecutorService pool = Executors.newFixedThreadPool(10);

        Future<Boolean> hTask = pool.submit(hJob);
        Future<Boolean> wTask = pool.submit(wJob);

        try {
            //返回执行结果
            boolean warterOk = hTask.get();
            boolean cupOk = wTask.get();

            Thread.currentThread().setName("主线程");
            if (warterOk && cupOk) {
                System.out.println("泡茶喝");
            } else if (!warterOk) {
                System.out.println("烧水失败,没有茶喝了");
            } else if (!cupOk) {
                System.out.println("杯子洗不了,没有茶喝了");
            }

        } catch (InterruptedException e) {
            System.out.println(getCurThreadName() + "发生异常被中断.");
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println(getCurThreadName() + " 运行结束.");
        //关闭线程池,释放资源
        pool.shutdown();
    }
}

通过这五种线程写法的整理,对多线程的理解是不是清晰多了,特别是最后一种方法写起来很简单;代码呢,还是需要反复体会的,最好多加练习,熟能生巧。

参考资料:
https://www.cnblogs.com/crazymakercircle/p/9904544.html

相关文章

  • 还不理解多线程,几个demo来搞定

    本文主要整理了关于多线程的五个demo,以demo来说明Java中多线程的演进之路,写法上是如何从繁到简的,这样更...

  • iOS多线程相关面试题

    iOS多线程demo iOS多线程之--NSThread iOS多线程之--GCD详解 iOS多线程之--NSOp...

  • 多线程之--NSOperation

    iOS多线程demo iOS多线程之--NSThread iOS多线程之--GCD详解 iOS多线程之--NSOp...

  • iOS多线程之--NSThread

    iOS多线程demo iOS多线程之--NSThread iOS多线程之--GCD详解 iOS多线程之--NSOp...

  • 【Java】【Thread多线程】概述

    多线程概述 通过子类继承开启多线程public class Demo { public static voi...

  • 2022-09-30 Friady 每日总结

    今日状态,还不错吧。 今日总结,今天打算把xx算法 Demo 搞定的。结果程序文案都好了,就差在一个交互上,没有找...

  • cocoapods的技术活

    1.先来理解一下cocoapods。了解cocoapods,先搞定几个单词:: RVM: Rub...

  • Java多线程的研究

    最近看了些关于多线程的文章,感觉还没有很深刻地理解,决定自己动手写几个例子来测试一下,加深对多线程的理解。 基础入...

  • 多线程(一)

    面试题 下面我们来看看几个例子 代码详见 gitHub_Demo 例1 例2 iOS中的常见多线程方案 GCD的...

  • 哪些你应该知道的多线程

    分类 普通多线程 demo 实现Runnable接口创建线程 ,可以实现一个Runnable接口 实用多线程 1....

网友评论

    本文标题:还不理解多线程,几个demo来搞定

    本文链接:https://www.haomeiwen.com/subject/rvlxictx.html