Java 多线程总结01

Java 多线程

  1. 什么是进程:

    进程是系统中正在运行的一个程序,程序一旦运行就是进程。

    进程可以看成程序执行的一个实例。进程是系统资源分配的独立实体,每个进程都拥有独立的地址空间。一个进程无法访问另一个进程的变量和数据结构,如果想让一个进程访问另一个进程的资源,需要使用进程间通信,比如管道,文件,套接字等。

  2. 什么是线程

    是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

  3. 线程的三种实现方式
    3.1继承Thread类

    Thread类构造方法:

    1.Thread();

    2.Thread(String name);

    3.Thread(Runable r);

    4.Thread(Runable r, String name);

    public class ExtendThread extends Thread {
        @Override
        public void run() {
           System.out.println("继承Thread类实现线程.......Name:"+this.getName()+" Id:"+this.getId());
        }
    
        public static void main(String[] args) {
            Thread thread = new ExtendThread();
            thread.start();
        }
    }
    

    Thread 类常用方法

    start();//启动线程

    getId();//获得线程ID

    getName();//获得线程名字

    getPriority();//获得优先权

    isAlive();//判断线程是否活动

    isDaemon();//判断是否守护线程

    getState();//获得线程状态

    sleep(long mill);//休眠线程

    join();//等待线程结束

    yield();//放弃cpu使用权利

    interrupt();//中断线程

    currentThread();//获得正在执行的线程对象

    3.2.实现Runnable接口
    public class ImpRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println("继承Runnable接口实现线程...");
            for(int i=0;i<10;i++){
                try {
                    Thread.sleep(1000);
                }catch (Exception e){
                    e.printStackTrace();
                }
    
                System.out.println(Thread.currentThread().getName()+"循环输出:"+i);
            }
        }
    
        public static void main(String[] args) {
            Runnable runnable = new ImpRunnable();
            Thread thread = new Thread(runnable);
            thread.start();
            for(int i=0;i<10;i++){
                try {
                    Thread.sleep(1000);
                }catch (Exception e){
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"循环输出:"+i);
            }
        }
    }
    
    3.3.使用Callable和Future

    Callable接口是一个泛型接口,也声明为了“函数式接口”。其唯一的抽象方法call有返回值,返回值的类型为泛型形参的实际类型。call抽象方法还有一个Exception的异常声明,容许方法内部的异常不经过捕获。

    @FunctionalInterface
    public interface Callable {
        /**
         * Computes a result, or throws an exception if unable to do so.
         *
         * @return computed result
         * @throws Exception if unable to compute a result
         */
        V call() throws Exception;
    }
    

    Callable接口与Runnable接口相比,还有一个很大的不同:Callable接口的实例不能作为Thread线程实例的target来使用;而Runnable接口实例可以作为Thread线程实例的target构造参数,开启一个Thread线程。由此引出在Callable实例和Thread 的target成员之间的一个搭桥的类——FutureTask类

    FutureTask类代表一个未来执行的任务,表示新线程所执行的操作。FutureTask类也位于java.util.concurrent包中。FutureTask类的构造函数的参数为Callable类型,实际上是对Callable类型的二次封装,可以执行Callable的call方法。FutureTask类间接地继承了Runnable接口,从而可以作为Thread实例的target执行目标。

    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
    

FutureTask内部有一个run方法。这个run方法是Runnable接口的抽象方法,在FutureTask类的内部提供了自己的实现。在Thread线程实例执行时,会将这个run方法作为target目标去异步执行。在FutureTask内部的run实现代码中,会执行其callable成员的call方法。执行完成后,将结果保存起来。FutureTask内部有另一个重要的成员——outcome属性,用于保存结果:outcome属性所保存的结果,可供FutureTask类的结果获取方法(如get)来获取。

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

public class CallThread implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        System.out.println("继承Callable接口实现线程...");
        for(int i=0;i<10;i++){
            try {
                Thread.sleep(1000);
            }catch (Exception e){
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName()+"循环输出:"+i);
        }
        return 1000;
    }

    public static void main(String[] args) throws Exception{
        Callable<Integer> callable = new CallThread();
        FutureTask<Integer> ft =new FutureTask<>(callable);
        Thread thread = new Thread(ft);
        thread.start();
        for(int i=0;i<10;i++){
            try {
                Thread.sleep(1000);
            }catch (Exception e){
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName()+"循环输出:"+i);
        }
        Integer integer = ft.get();//注意i此方法会阻塞当前线程直到获取到返回结果
        System.out.println("Callable 接口返回值"+integer);
    }
}
4. Guava 的异步回调

Guava 是谷歌公司提供的Java扩展包,提供了一种异步回调的解决方案,包中的很多类,都是对java.util.concurrent能力的扩展和增强。例如,Guava的异步任务接口ListenableFuture,扩展了Java的Future接口,实现了非阻塞获取异步结果的功能。

4.1 Guava对Java的异步回调机制,做了以下的增强:

(1)引入了一个新的接口ListenableFuture,继承了Java的Future接口,使得Java的Future异步任务,在Guava中能被监控和获得非阻塞异步执行的结果。

(2)引入了一个新的接口FutureCallback,这是一个独立的新接口。该接口的目的,是在异步任务执行完成后,根据异步结果,完成不同的回调处理,并且可以处理异步结果。

4.2 详解FutureCallback

FutureCallback是一个新增的接口,用来填写异步任务执行完后的监听逻辑。FutureCallback拥有两个回调方法:(1)onSuccess方法,在异步任务执行成功后被回调;调用时,异步任务的执行结果,作为onSuccess方法的参数被传入。

(2)onFailure方法,在异步任务执行过程中,抛出异常时被回调;调用时,异步任务所抛出的异常,作为onFailure方法的参数被传入。

@GwtCompatible
public interface FutureCallback<V> {
    void onSuccess(@Nullable V var1);

    void onFailure(Throwable var1);
}

Guava的FutureCallback与Java的Callable的区别:

(1)Java的Callable接口,代表的是异步执行的逻辑。

(2)Guava的FutureCallback接口,代表的是Callable异步逻辑执行完成之后,根据成功或者异常两种情况,所需要执行的善后工作。

4.3 详解ListenableFuture

Guava的ListenableFuture接口是对Java的Future接口的扩展.

ListenableFuture仅仅增加了一个方法——addListener方法。它的作用就是将前一小节的FutureCallback善后回调工作,封装成一个内部的Runnable异步回调任务,在Callable异步任务完成后,回调FutureCallback进行善后处理。

在实际编程中,可以使用Guava的Futures工具类,它有一个addCallback静态方法,可以将FutureCallback的回调实例绑定到ListenableFuture异步任务。

Java 多线程总结01_第1张图片

Guava异步回调的流程如下:

第1步:实现Java的Callable接口,创建异步执行逻辑。还有一种情况,如果不需要返回值,异步执行逻辑也可以实现Java的Runnable接口。

第2步:创建Guava线程池。

第3步:将第1步创建的Callable/Runnable异步执行逻辑的实例,通过submit提交到Guava线程池,从而获取ListenableFuture异步任务实例。

第4步:创建FutureCallback回调实例,通过Futures.addCallback将回调实例绑定到ListenableFuture异步任务上。完成以上四步,当Callable/Runnable异步执行逻辑完成后,就会回调异步回调实例FutureCallback的回调方法onSuccess/onFailure。

泡茶案例

import com.crazymakercircle.util.Logger;
import com.google.common.util.concurrent.*;

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

/**
 * Created by 尼恩 at 疯狂创客圈
 */

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 //②
        {

            try {
                Logger.info("洗好水壶");
                Logger.info("灌上凉水");
                Logger.info("放在火上");

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

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

            return true;
        }
    }

    static class WashJob implements Callable<Boolean> {

        @Override
        public Boolean call() throws Exception {


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

            } catch (InterruptedException e) {
                Logger.info(" 清洗工作 发生异常被中断.");
                return false;
            }
            Logger.info(" 清洗工作  运行结束.");
            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);
                    Logger.info("读书中......");
                } catch (InterruptedException e) {
                    Logger.info(getCurThreadName() + "发生异常被中断.");
                }

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


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

        }
    }

    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) {
                Logger.info("烧水失败,没有茶喝了");
            }
        });
        //提交清洗的业务逻辑,取到异步任务

        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) {
                Logger.info("杯子洗不了,没有茶喝了");
            }
        });
    }


}
      //绑定任务执行完成后的回调,到异步任务
        Futures.addCallback(washFuture, new FutureCallback<Boolean>() {
            public void onSuccess(Boolean r) {
                if (r) {
                    mainJob.cupOk = true;
                }
            }

            public void onFailure(Throwable t) {
                Logger.info("杯子洗不了,没有茶喝了");
            }
        });
    }


}

你可能感兴趣的:(JAVA,学习笔记,多线程,java)