美文网首页
java多线程与线程池

java多线程与线程池

作者: xSpringCloud | 来源:发表于2018-06-05 09:41 被阅读0次

第一部分 多线程

1.1 多线程介绍:

进程:进程指正在运行的程序。确切的来说,当一个程序进入内存运行,即变为一个进程,进程是处于运行过程中的程序,并且具有一定的独立功能;
线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个程序运行后至少有一个线程, 一个进程中可以包含多个线程;

1.2 Thread类:

构造方法:
Thread():分配新的Thread对象;
Thread(String name):分配新的Thread对象,将指定的name作为其线程名称;
常用方法:
void start():使该线程开始执行;java虚拟机调用该线程的run方法;
void run():线程要执行的操作;
static void sleep(long millis):在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)

1.3 创建线程方式-继承Thread类

测试类:

 public static void main(String[] args) {
        //创建自定义线程对象
        MyThread myThread = new MyThread("新的线程");
        //开启新线程
        myThread.start();
        for (int i = 0; i < 100; i++) {
            System.out.println("main线程正在运行"+ i);
        }
    }

自定义Thread类:

public class MyThread extends Thread {

    //定义指定线程名称的构造方法
    public MyThread(String name) {
        //调用父类的String参数的构造方法,指定线程的名称
        super(name);
    }
    @Override
    public void run(){
        for (int i = 0; i < 100; i++) {
            System.out.println(getName() + "正在执行"+ i);
        }
    }
}

1.4 创建线程方式-实现Runnable接口

自定义线程执行任务类:

public class MyRunnable implements Runnable {
    @Override
    public void run(){
        for (int i = 0; i < 100 ; i++) {
            System.out.println("自定义线程正在执行"+i);
        }
    }
}

测试类:

public class test {
    public static void main(String[] args) {
        //创建线程目标执行类对象
        MyRunnable runn = new MyRunnable();
        //将Runnable接口的子类对象作为参数传递给Thread类的构造函数
        Thread thread = new Thread(runn);
        Thread thread1 = new Thread(runn);
        //开启线程
        thread.start();
        thread1.start();
        for (int i = 0; i < 100; i++) {
            System.out.println("main线程正在运行"+i);
        }

    }
}

1.5两种创建线程方式的区别:

实现Runnable接口,避免了继承Thread类的单继承局限性。覆盖Runnable接口中的run方法,将线程任务代码定义到run中;
实现Runnable接口的方式,更加的符合面向对象,线程分为两部分,一部分线程对象,一部分线程任务。继承Thread类,线程对象和线程任务耦合在一起。一旦创建Thread类的子类对象,既是线程对象,有又有线程任务。实现runnable接口,将线程任务单独分离出来封装成对象,类型就是Runnable接口类型。Runnable接口对线程对象和线程任务进行解耦

第二部分 线程池

线程池能够复用线程,减少线程的创建,销毁,恢复等状态切换的开销,提高程序的性能。一个线程池管理了一组工作线程,同时它还包括了一个用于放置等待执行的任务的队列;

2.1 ExecutorService 线程池

2.1.1 ExecutorService的创建

创建一个什么样的ExecutorService的实例(即线程池)需要各部根据具体的应用场景而定,java提供了Executors工厂类,可以很方便的创建各种类型的ExecutorService线程池,Executors可以创建下面四类线程池:

  1. newCachedThreadPool :创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
  2. newFixedThreadPool :创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
  3. newScheduledThreadPool:创建一个定长线程池,支持定时或周期性的执行任务;
  4. newSingleThreadExecutor :创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO,LIFO,优先级)执行;

备注:Executors只是一个工厂类,它所有的方法返回的都是ThreadPoolExecutor、ScheduledThreadPoolExecutor这两个类的实例

2.1.2 ExecutorService的使用

public static void main(String[] args) {
        //定义了包含10线程的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("task is doing");
            }
        });
        executorService.shutdown();
    }

2.1.3 ExecutorService的执行

ExecutorService有以下几个执行方法

  1. execute(Runnable)
  2. submit(Runnable)
  3. submit(Callable)
  4. invokeAny(...)
  5. invokeAll(...)

2.1.3.1 execute(Runnable)

这个方法接收一个Runnable实例,并且异步的执行:

public static void main(String[] args) {
        //定义了包含10线程的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("task is doing");
            }
        });
        System.out.println("other work is doing");
        executorService.shutdown();
    }

执行结果:

other work is doing
task is doing

缺点:没法获取task的执行结果

2.1.3.2 submit(Runnable)

public static void main(String[] args) throws Exception{
       ExecutorService executorService = Executors.newFixedThreadPool(10);
       Future future = executorService.submit(new Runnable() {
           @Override
           public void run() {
               System.out.println("task is doing");
           }
       });
       System.out.println("other work is doing");
       executorService.shutdown();
       //如果任务执行完成,future.get()方法会返回一个null,future.get()方法会产生阻塞
       future.get();
       System.out.println(future.get());
        System.out.println("task is finish");
   }

执行结果:

other work is doing
task is doing
null
task is finish

2.1.3.3 submit(Callable)

submit(Callable)和submit(Runnable)类似,也会返回一个Future对象,但是除此之外,submit(Callable)可以返回任务的执行结果

 public static void main(String[] args) throws Exception{
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        Future future = executorService.submit(new Callable<Object>() {
            public Object call() throws Exception {
                System.out.println("task is doing");
                return "Callable Result";
            }
        });
        System.out.println("other work is doing");
        executorService.shutdown();
        //如果任务执行完成,future.get()方法会返回一个null,future.get()方法会产生阻塞
        future.get();
        System.out.println("task is finish");
        System.out.println(future.get());
    }

执行结果:

other work is doing
task is doing
task is finish
Callable Result

多线程执行:

public static void main(String[] args) throws Exception{
       ExecutorService executorService = Executors.newFixedThreadPool(5);
       List<Future> futures = new ArrayList<>();
       int cnt=0;
       for (int i = 0; i < 5; i++) {
            futures.add(executorService.submit(new Callable<Object>() {
               public Object call() throws Exception {
                   System.out.println(Thread.currentThread().getName());
                   return Thread.currentThread().getName() + " callable Result";
               }
           }));
       }
       System.out.println("other work is doing");
       //如果任务执行完成,future.get()方法会返回一个null,future.get()方法会产生阻塞
       for(Future future : futures){
           System.out.println(future.get());
       }
       System.out.println("task is finish");
       executorService.shutdown();
   }

执行结果:

pool-1-thread-1
other work is doing
pool-1-thread-2
pool-1-thread-4
pool-1-thread-1 callable Result
pool-1-thread-2 callable Result
pool-1-thread-5
pool-1-thread-3
pool-1-thread-3 callable Result
pool-1-thread-4 callable Result
pool-1-thread-5 callable Result
task is finish

如果任务执行完成,future.get()方法会返回Callable任务的执行结果。注意,future.get()方法会产生阻塞

2.1.3.4 invokeAny(…)

invokeAny(...)方法接收的是一个Callable的集合,执行这个方法不会返回Future,但是会返回所有Callable任务中其中一个任务的执行结果。这个方法也无法保证返回的是哪个任务的执行结果,反正是其中的某一个
机制:如果 集合中的某个task,完成了(或者抛出异常),那么集合中剩余的task将全部会被取消,不会得到执行

 public static void main(String[] args) throws Exception{
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Set<Callable<String>> callables = new HashSet<Callable<String>>();
        callables.add(new Callable<String>() {
            public String call() throws Exception {
                return "Task 1";
            }
        });
        callables.add(new Callable<String>() {
            public String call() throws Exception {
                return "Task 2";
            }
        });
        callables.add(new Callable<String>() {
            public String call() throws Exception {
                return "Task 3";
            }
        });

        String result = executorService.invokeAny(callables);
        System.out.println("result = " + result);
        executorService.shutdown();
    }

执行结果:

result = Task 2 或者 result = Task 1 或者 result = Task 3

2.1.3.4 invokeAll(…)

方法invokeAll会调用存在于参数集合中的所有Callable对象,并且返回一个包含Future对象的集合,你可以通过这个返回的集合管理每个Callable的执行结果;
需要注意的是,任务有可能因为异常而导致运行结束,所以它可能并不是真的成功运行了。但是我们没有办法通过 Future 对象来了解到这個差异

public static void main(String[] args) throws Exception{
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Set<Callable<String>> callables = new HashSet<Callable<String>>();
        callables.add(new Callable<String>() {
            public String call() throws Exception {
                return "Task 1";
            }
        });
        callables.add(new Callable<String>() {
            public String call() throws Exception {
                return "Task 2";
            }
        });
        callables.add(new Callable<String>() {
            public String call() throws Exception {
                return "Task 3";
            }
        });
        callables.add(new Callable<String>() {
            public String call() throws Exception {
                return "Task 4";
            }
        });

        List<Future<String>> futures = executorService.invokeAll(callables);
        System.out.println("other work is doing");
        for(Future<String> future :futures ){
            System.out.println("result = " + future.get());
        }
        System.out.println("task is finish");
        executorService.shutdown();
    }

执行结果:

other work is doing
result = Task 2
result = Task 4
result = Task 1
result = Task 3
task is finish

2.1.4 ExecutorService Shutdown关闭

当你使用ExecutorService的时候,你应该记得关闭它,这样这些被管理的线程才会停止运行。

举例:如果你的应用通过main()方法启动,并且你的 应用中存在一个 激活的 ExecutorService,那么即使你的main thread(main线程)已经退出了,这个应用依然会在后台运行。 原因: ExecutorService中的活跃线程,防止了jvm关闭ExecutorService。

结论:jvm是可能无法关闭ExecutorService的,如果某些情况下,你不希望ExecutorService在后台不受控制的执行,那你在必要的时候 需要手动调用 ExecutorService中的shutdown方法。

通过调用ExecutorService中的shutdown方法可以终止该ExecutorService中的线程,但是ExecutorService并不会立即关闭,但是ExecutorService已经不会再接收新的task了,等到所有的thread完成各自的task,那么这个ExecutorService就会关闭。并且所有task中的结果 会在shutdown方法执行之前 submit(提交),都是已经执行完成了的。并不会存在没有的执行的task。

结论:手动调用shutdown并不会立即关闭ExecutorService,而是等待ExecutorService中所有的任务完成,并且提交之后,才会关闭的。(所以手动调用shotdown方法,可以不必担心存在剩余任务没有执行的情况)

如果你想立即关闭一个ExecutorService,你可以调用shutdownNow方法来实现。调用这个方法,ExecutorService将会”尝试着“关闭所有正在执行的task,这个关闭的过程会自动跳过那些已经submit的task(节省性能)。但是 对于那些正在 执行的task,并不能保证他们就一定会直接停止执行,或许他们会暂停,或许会执行直到完成,但是ExecutorService会尽力关闭所有正在运行的task。

相关文章

  • Java:线程池Executors.newFixedThread

    摘要:Java,多线程,线程池 多线程编程和线程池概述 (1)多线程程序: 计算机可以实现多任务 ( multit...

  • JAVA 多线程与锁

    JAVA 多线程与锁 线程与线程池 线程安全可能出现的场景 共享变量资源多线程间的操作。 依赖时序的操作。 不同数...

  • 10.3多线程详解

    Java高级-多线程 多线程创建 多线程通讯 线程池 1.多线程创建 thread/runnable图:继承Thr...

  • 线程

    Java 并发编程:线程池的使用 Java 并发编程:线程池的使用java 多线程核心技术梳理 (附源码) 本文对...

  • Java源码-线程池

    一、线程池实现原理 Java支持多线程,多线程可以提高任务的执行效率。但是Java里面的线程跟操作系统的线程是一一...

  • Java面试题——多线程

    Java面试题——多线程 1,什么是线程池? 线程池是多线程的一种处理方式,处理过程中将任务提交给线程池,任务执行...

  • 阿里巴巴Java高级岗必问面试题总结:JVM+多线程+网络+Re

    阿里巴巴Java高级岗必问面试题总结 一、Java多线程相关 线程池的原理,为什么要创建线程池?创建线程池的方式;...

  • 线程的并发工具类

    Java 下多线程的开发我们可以自己启用多线程,线程池,除此之外,Java还为我们提供了Fork-Join、Cou...

  • JAVA并发编程(1)

    一、常用的一些JAVA线程池框架与说明 二、如何进行并发编程(一个单元测试例子)(1)选择JAVA多线程框架与线程...

  • 反射、注解与依赖注入总结

    上一篇【线程、多线程与线程池总结】中主要记录线程、多线程相关概念,侧重于线程的Future使用与线程池的操作;同样...

网友评论

      本文标题:java多线程与线程池

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