• JAVA总结多线程


    一、概念

      1.进程:一个具有一定独立功能的程序,关于某些数据集合,一次运行活动。 两点:1、有自己的空间存储数据;2、一个程序。  

       进程,是系统   进行   资源分配  和 调度  的基础单位。动态性,独立性,并发性,异步性,结构特征(程序、数据、进程控制块)

       进程控制块,为  管理进程  而设置的数据结构,用于描述进程过程或者进程状态的变化过程。包括:程序计数器(指令地址)、CPU暂存器(累加器、堆栈指针)等等

     2. 线程:程序执行的最小单位;单一顺序控制流程;

      通常,一个进程包含多个线程,进程:资源分配,线程:独立运行、独立调度;

     二、状态

    1. 新建状态(New):新创建了一个线程对象。

    2. 就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。

    3. 运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。

    4. 阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:

    (一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
    (二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
    (三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

    sleep与wait的区别

    1、所属类:sleep是thread的方法;wait是Object的方法;

    2、锁释放:sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法;

    3、使用范围:wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用;

    4、sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常;

    三、线程的使用

    1、多线程的实现方式--无返参

    1 public abstract interface Runnable
    2 {
    3   public abstract void run();
    4 }

    实现接口Runnable:重写run()方法,封装Thread类,并通过start()方法实现线程的启动。

    1 public class Thread  implements Runnable

    继承父类Thread:重写run()方法,实例化对象并调用start()方法,即可实现线程的启动。

    而start()方法,由jvm识别并调用run()方法。

    java类仅仅支持继承一个父类,但是可以实现多个接口,所以,尽量以Runnable接口的形式实现多线程。

    多次调用同一线程对象的start()方法,会报错提示IllegalThreadStateException

    2、多线程的实现方式--有返参

    带返参的线程

    1 public interface Callable<V> {
    2     V call() throws Exception;
    3 }

    实现接口Callable:重写call方法

    扩展接口:Future:get等方法,RunnableFuture:继承两个接口Runnable 和Future;

    实现类FutureTask :实现RunnableFuture

     1 public abstract interface Future<V>
     2 {
     3   public abstract boolean cancel(boolean paramBoolean);
     4 
     5   public abstract boolean isCancelled();
     6 
     7   public abstract boolean isDone();
     8 
     9   public abstract V get()
    10     throws InterruptedException, ExecutionException;
    11 
    12   public abstract V get(long paramLong, TimeUnit paramTimeUnit)
    13     throws InterruptedException, ExecutionException, TimeoutException;
    14 }

    RunnableFuture接口

    1 public abstract interface RunnableFuture<V> extends Runnable, Future<V>
    2 {
    3   public abstract void run();
    4 }

    FutureTask 

    1 Callable<String> callable = new CallableImpl("my callable test!");
    2 FutureTask<String> task = new FutureTask<>(callable);
    3 new Thread(task).start();
    4 String result = task.get();

    3、线程池--生产者消费者模式

     概念:综合管理线程,减少处理器的闲置时间,提高服务性能 ;尤其应用于场景:创建线程时间+销毁线程时间>线程运行时间;

     Executor 是 Java 线程池的核心接口,用来并发执行提交的任务;提供execute()方法用来提交任务;无返参;不支持取消;

    1 public abstract interface Executor
    2 {
    3   public abstract void execute(Runnable paramRunnable);
    4 }

    ExecutorService 是 Executor 接口的扩展,提供了异步执行和关闭线程池的方法;提供submit()方法用来提交任务; submit()方法可以接受RunnableCallable接口的对象;Future对象可以实现线程的取消和返参获取;shutDown()方法关闭线程池;

     1 public abstract interface ExecutorService extends Executor
     2 {
     3   public abstract void shutdown();
     4 
     5   public abstract List<Runnable> shutdownNow();
     6 
     7   public abstract boolean isShutdown();
     8 
     9   public abstract boolean isTerminated();
    10 
    11   public abstract boolean awaitTermination(long paramLong, TimeUnit paramTimeUnit)
    12     throws InterruptedException;
    13 
    14   public abstract <T> Future<T> submit(Callable<T> paramCallable);
    15 
    16   public abstract <T> Future<T> submit(Runnable paramRunnable, T paramT);
    17 
    18   public abstract Future<?> submit(Runnable paramRunnable);
    19 
    20   public abstract <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> paramCollection)
    21     throws InterruptedException;
    22 
    23   public abstract <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> paramCollection, long paramLong, TimeUnit paramTimeUnit)
    24     throws InterruptedException;
    25 
    26   public abstract <T> T invokeAny(Collection<? extends Callable<T>> paramCollection)
    27     throws InterruptedException, ExecutionException;
    28 
    29   public abstract <T> T invokeAny(Collection<? extends Callable<T>> paramCollection, long paramLong, TimeUnit paramTimeUnit)
    30     throws InterruptedException, ExecutionException, TimeoutException;
    31 }

    Executors 是一个工具类;提供工厂方法来创建不同类型的线程池;

    Executor vs ExecutorService vs Executors

    正如上面所说,这三者均是 Executor 框架中的一部分。Java 开发者很有必要学习和理解他们,以便更高效的使用 Java 提供的不同类型的线程池。总结一下这三者间的区别,以便大家更好的理解:

    • Executor 和 ExecutorService 这两个接口主要的区别是:ExecutorService 接口继承了 Executor 接口,是 Executor 的子接口
    • Executor 和 ExecutorService 第二个区别是:Executor 接口定义了 execute()方法用来接收一个Runnable接口的对象,而 ExecutorService 接口中的 submit()方法可以接受RunnableCallable接口的对象。
    • Executor 和 ExecutorService 接口第三个区别是 Executor 中的 execute() 方法不返回任何结果,而 ExecutorService 中的 submit()方法可以通过一个 Future 对象返回运算结果。
    • Executor 和 ExecutorService 接口第四个区别是除了允许客户端提交一个任务,ExecutorService 还提供用来控制线程池的方法。比如:调用 shutDown() 方法终止线程池。可以通过 《Java Concurrency in Practice》 一书了解更多关于关闭线程池和如何处理 pending 的任务的知识。
    • Executors 类提供工厂方法用来创建不同类型的线程池。比如: newSingleThreadExecutor() 创建一个只有一个线程的线程池,newFixedThreadPool(int numOfThreads)来创建固定线程数的线程池,newCachedThreadPool()可以根据需要创建新的线程,但如果已有线程是空闲的会重用已有线程。

    4种类型的线程池

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

     1   // 创建一个可重用固定线程数的线程池  
     2         ExecutorService pool = Executors.newFixedThreadPool(3);  
     3         // 创建线程  
     4         Thread t1 = new MyThread();  
     5         Thread t2 = new MyThread();  
     6         // 将线程放入池中进行执行  
     7         pool.execute(t1);  
     8         pool.execute(t2);  
     9         // 关闭线程池  
    10         pool.shutdown();  
     1 public class FutureTaskExample {
     2      public static void main(String[] args) {
     3         MyCallable callable1 = new MyCallable(1000);                       // 要执行的任务
     4          MyCallable callable2 = new MyCallable(2000);
     5 
     6         FutureTask<String> futureTask1 = new FutureTask<String>(callable1);// 将Callable写的任务封装到一个由执行者调度的FutureTask对象
     7          FutureTask<String> futureTask2 = new FutureTask<String>(callable2);
     8  
     9         ExecutorService executor = Executors.newFixedThreadPool(2);        // 创建线程池并返回ExecutorService实例
    10          executor.execute(futureTask1);  // 执行任务
    11          executor.execute(futureTask2);  
    12          
    13         while (true) {
    14             try {
    15                 if(futureTask1.isDone() && futureTask2.isDone()){//  两个任务都完成
    16                     System.out.println("Done");
    17                     executor.shutdown();                          // 关闭线程池和服务 
    18                     return;
    19                 }
    20                  
    21                 if(!futureTask1.isDone()){ // 任务1没有完成,会等待,直到任务完成
    22                     System.out.println("FutureTask1 output="+futureTask1.get());
    23                 }
    24                
    25                 System.out.println("Waiting for FutureTask2 to complete");
    26                 String s = futureTask2.get(200L, TimeUnit.MILLISECONDS);
    27                 if(s !=null){
    28                     System.out.println("FutureTask2 output="+s);
    29                 }
    30             } catch (InterruptedException | ExecutionException e) {
    31                 e.printStackTrace();
    32             }catch(TimeoutException e){
    33                 //do nothing
    34             }
    35         }
    36     }
    37 }
    
    



  • 相关阅读:
    继承与 接口
    数组
    字符串加密
    类与对象
    java 方法学习
    课堂练习
    第一次课堂任务记录。整形数字相加合输出
    《大道至简》第二章 读后感
    大道至简第二章
    大道至简第一章
  • 原文地址:https://www.cnblogs.com/huasky/p/7543975.html
Copyright © 2020-2023  润新知