常用线程池接口和类

线程池

  • 线程容器,可设定线程分配的数量上限。
  • 将预先创建的线程对象存入池中,并重用线程池中的线程对象。
  • 避免频繁的创建和销毁。

常用线程池接口和类(所在包java.util.concurrent):

  • Executor: 线程池顶级接口。

  • ExecutorService:线程池接口,可通过submit(Runnable task)提交任务。

  • Executors工具类:通过此类可以获得一个线程池。

  • 通过newFixedThreadPool(int nThreads):获取固定数量的线程池。参数:指定线程池中线程的数量。

  • newCashedThreadPool():获得动态数量的线程池,如不够则重新创建新的,没有上限。

  • 代码实现

package com.sun.base.XianCheng;

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

/**
 * 演示线程池的创建
 * Executor :线程池的根接口,executor()
 * ExecutorService:包含管理线程池的一些方法,submit、shutdown
 *      ThreadPoolExecutor
 *         ScheduledThreadPoolExecutor
 * Executors:创建线程池的工具类
 *        (1)创建固定线程个数线程池
 *        (2)创建动态线程池
 *        (3)创建单线程池
 *        (4)创建调度线程池  调度:周期、定时执行
 */
public class Demo01 {
    public static void main(String[] args){
        //创建固定个数的线程池
       // ExecutorService es=Executors.newFixedThreadPool(5);
        //创建动态线程池
        ExecutorService es=Executors.newCachedThreadPool();
        //创建单线程线程池
        //Executors.newSingleThreadExecutor();
        //创建调度线程池
        //Executors.newScheduledThreadPool();
        // 创建任务
        Runnable runnable=new Runnable() {
            private int ticket=100;
            @Override
            public void run() {
                while (true){
                    if (ticket<=0){
                        break;
                    }
                    System.out.println(Thread.currentThread().getName()+"卖了第"+ticket+"张票");
                    ticket--;
                }
            }
        };
        //提交任务
        for (int i =0;i<5;i++){//5=上面的线程池个数
            es.submit(runnable);
        }
        //关闭线程池
        es.shutdown();
    }
}

  • Callable接口

public interface Callable{
public V call() throws Exception;
}


​    -1、与Runnable接口类似,实现之后代表一个接口任务。

​    -2、Callable具有泛型返回值、可以声明异常。  

```java
package com.sun.base.XianCheng;

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

/**
* 演示Callable接口的使用
* Callable与Runnable接口的区别:
* ​    1、Callable中call方法具有泛型返回值、Runnable接口中run方法没有返回值
*     2、Callable中call方法可以声明异常,Runnable接口中run方法没有异常
*/
public class Demo02 {
  public static void main(String[] args) throws ExecutionException, InterruptedException {
      //功能需求,使用Callable实现1-100的和
      //1、创建Callable对象
      Callable<Integer> callable=new Callable<Integer>() {
          @Override
          public Integer call() throws Exception {
              System.out.println(Thread.currentThread().getName()+"开始计算");
              int sum=0;
              for (int i=0;i<=100;i++){
                  sum+=i;
              }
              return sum;
          }
      };
     //把Callable对象转成任务
      FutureTask<Integer> task=new FutureTask<>(callable);
      //创建线程
      Thread thread=new Thread(task);
      thread.start();
      //获取结果
      Integer sum = task.get();
      System.out.println("计算结果是:"+sum);
  }
}
  • Future接口

    • Future:表示将要完成任务的结果。
  • 线程池+Callable接口+Future+接口的综合使用

package com.sun.base.XianCheng;

import java.util.concurrent.*;

/**
 * 要求:计算1-100的和
 *    使用两个线程,并发计算1-50、51-100的和,再进行汇总统计。
 */
public class Demo03 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建线程池
        ExecutorService es = Executors.newFixedThreadPool(2);
        //提交任务
        Future<Integer> future=es.submit(new Callable<Integer>() {
            private int sum=0;
            @Override
            public Integer call() throws Exception {
                System.out.println(Thread.currentThread().getName()+"开始计算");
                for (int i=0;i<=50;i++){
                    sum+=i;
                }
                return sum;
            }
        });
        Future<Integer> future2=es.submit(new Callable<Integer>() {
            private int sum=0;
            @Override
            public Integer call() throws Exception {
                System.out.println(Thread.currentThread().getName()+"开始计算");
                for (int i=51;i<=100;i++){
                    sum+=i;
                }
                return sum;
            }
        });
        //汇总
        int sum=future.get()+future2.get();
        System.out.println("计算结果是:"+sum);
    }
}
  • 线程同步(单条执行路径)

    • 形容一次方法调用,同步一旦开始,调用者必须等待该方法返回,才能继续。(只要有等待就是同步
  • 线程异步(多条执行路径)

    • 形容一次方法调用,异步一旦开始,像是一次消息传递,调用者告知之后立刻返回。二者竞争时间片,并发执行。
  • Lock接口

    • 与synchronized比较,显示定义,结构更灵活。

    • 提供更多实用性方法,功能更强大、性能更优越。

    • 常用方法:

      void lock() //获取锁,如锁被占用,则等待。

      boolean tryLock() //尝试获取锁(成功返回true,失败返回false,不阻塞)。

      void unlock() //释放锁。

    • 重入锁

      ReentrantLock:Lock接口的实现类,与synchronized一样具有互斥锁功能。

      Lock lock=new ReentrantLock;
      ...
      lock.lock();//上锁
      try{
          ...
      }finally{
          lock.unlock();//释放锁
      }
      
    • 读写锁ReentrantReadWriteLock

      一种支持一写多读的同步锁,读写分离,可分别分配读锁、写锁。

      支持多次分配读锁,使多个读操作可以并发执行。

      互斥规则:

      • 写-写:互斥,阻塞。
      • 读-写:互斥,读阻塞写,写阻塞读。
      • 读-读:不互斥,不阻塞。
      • 在读操作远远高于写操作的环境下,可在保障线程安全的情况下,提高运行效率。
ReentrantReadWriteLock rwl=new ReentrantReadWriteLock();//创建读写锁
ReadLock readLock= rwl.readLock();//获得读锁
WriteLock writeLock= rwl.writeLock();//获得写锁
posted @ 2020-12-11 16:42  某人很酷  阅读(368)  评论(0)    收藏  举报