线程的创建

1. 线程的创建方式

  1. 继承Thread
  2. 实现Runnble接口
  3. 实现callable接口
  4. 线程池创建

2. 继承Thread类

2.1 实现方式

  1. 创建一个继承于Thread类的子类
  2. 重写Thread类的run() —> 将此线程执行的操作声明在run()中
  3. 创建Thread类的子类的对象
  4. 通过此对象调用start():①启动当前线程 ② 调用当前线程的run()

    2.2 代码示例

    1. public class extendsThread {
    2. public static void main(String[] args) {
    3. // 3、new Thread对象
    4. exThread exThread = new exThread();
    5. // 4、调用start()启动线程
    6. exThread.start();
    7. }
    8. }
    9. // 1、继承Thread类
    10. class exThread extends Thread {
    11. @Override
    12. // 2、重写run方法
    13. public void run() {
    14. System.out.println("使用继承Thread类,来创建线程");
    15. }
    16. }

    线程的创建 - 图1

    3. 实现Runnable接口

    3.1 实现方式

  5. 创建一个实现Runnable接口的类

  6. 覆写run()方法
  7. 创建实现类的对象
  8. 将此对象作为参数传递到Thread类的构造器中,创建Thread对象
  9. 通过Thread类的对象调用start()

3.2 代码示例

/**
 * @author zongzhaojin
 * @date 2022/4/16 11:12
 */
public class RunnableTest {
    public static void main(String[] args) {
        // 3. 创建实现类
        GetRunnable getRunnable = new GetRunnable();
        // 4. 新建Thread对象,将实现类传入
        Thread thread = new Thread(getRunnable);
        // 5. 调用Thread对象的start()方法
        thread.start();
    }
}
// 1. 实现Runnable接口
class GetRunnable implements Runnable{
    // 2. 重写Run方法
    @Override
    public void run() {
        System.out.println("通过实现Runnable接口来创建一个线程");
    }
}

3. 实现Callable接口

3.1 实现方式

  1. 创建一个实现Callable的实现类
  2. 实现call方法
  3. 创建实现类对象
  4. 将实现类传入FutureTask构造器中,创建FutureTask的对象
  5. 将FutureTask的对象传入Thread类构造器中,创建Thread对象,并调用start()
  6. 通过FutureTask对象获取call方法的返回值

    3.2 代码示例

    /**
    * @author zongzhaojin
    * @date 2022/4/15 19:11
    */
    public class callThread {
     public static void main(String[] args) {
         // 3. 创建实现类的对象
         MyThread myThread = new MyThread();
         // 4.将实现类对象传入FutureTask构造函数中 创建FutureTask对象 支持泛型
         FutureTask<String> futureTask = new FutureTask(myThread);
         // 5. 将futureTask对象传入Thread构造器中 创建对象 并调用start()方法
         new Thread(futureTask).start();
         try {
             String str = futureTask.get();
             System.out.println(str);
         } catch (InterruptedException e) {
             e.printStackTrace();
         } catch (ExecutionException e) {
             e.printStackTrace();
         }
     }
    }
    // 1.实现Callable接口
    class MyThread implements Callable{
     // 2. 实现call方法
     @Override
     public Object call() throws Exception {
         for(int i = 0;i<10;i++){
             System.out.println(i);
         }
         return "成功返回";
     }
    }
    

    4. 使用线程池来创建线程

    4.1 线程池的参数

  7. corePoolSize: 核心线程数量,当有新任务在execute()方法提交时,会执行以下判断:

    1. 如果运行的线程少于corePoolSize,则创建新线程来处理任务,即使线程池中的其他线程是空闲的
    2. 如果线程池中的线程数量大于等于corePoolSize且小于maximumPoolSize,则只有当workQueue满时才创建新的线程去处理任务
    3. 如果corePoolSizemaximumPoolSize相同,则创建的线程池大小是固定的,这时如果有新任务提交,若workQueue未满,则将请求放入workQueue中,等待有空闲的线程去从workQueue中取任务并处理
    4. 如果运行的线程数量大于等于maximumPoolSize,这时候workQueue已经满了,则通过handler所指定的策略来处理任务;

所以,在任务提交时,判断的顺序为 corepoolSize —> workQueue —> maximumPoolSize

  1. maximumPoolSize: 最大线程数量
  2. workQueue: 等待队列,当任务提交时,如果线程池中的线程数量大于等于corePoolSize的时候,把任务封装成一个Worker对象放入等待队列;workQueue 主要有以下几种处理方式:
    1. 直接切换:这种方式常用的队列是SynchronousQueue
    2. 无界队列:一般使用基于链表的阻塞队列LinkedBlockIngQueue。如果使用这种方式,那么线程池能够创建的最大线程数就是corePoolSize。而maximumPoolSize就不会起作用了。
    3. 有界队列:一帮使用ArrayBlockingQueue,使用该方式可以将线程池的最大线程数量限制为maximumPoolSize,这样能够降低资源的消耗,但是需要注意如果worker足够多,会频繁调用handler策略
  3. keepAliveTime: 线程池维护线程允许的空闲时间。当线程池中的线程数量大于corePoolSize的时候,如果没有新的任务提交,核心线程外的线程不会立即销毁,二十等待,直到等待时间超过keepAliveTime,在进行销毁。
  4. threadFactory: 它是ThreadFactory类型的变量,用来创建新线程。默认是使用Executors.defaultThreadFactory()来创建线程。使用默认的ThreadFactory来创建线程时,会使新创建的线程具有相同的NORM_PRIORITY优先级并且是非守护线程,同时也设置了线程的名称。
  5. handler: 它是RejectedExecutionHandler类型的变量,表示线程池的饱和策略。如果阻塞队列满了并且没有空闲的线程,这时如果继续提交任务,就需要采取一种策略处理该任务。线程池提供了4种策略:
    1. AbortPolicy: 直接抛出异常,这是默认策略;
    2. CallerRunsPolicy: 用调用者所在的线程来执行任务
    3. DiscardOldestPolicy: 丢弃阻塞队列中最靠前的任务,并执行当前任务;
    4. DiscardPolicy:直接丢弃任务
  6. TimeUnit: 存活时间的单位:

    TimeUnit.DAYS;               //天
    TimeUnit.HOURS;             //小时
    TimeUnit.MINUTES;           //分钟
    TimeUnit.SECONDS;           //秒
    TimeUnit.MILLISECONDS;      //毫秒
    TimeUnit.MICROSECONDS;      //微妙
    TimeUnit.NANOSECONDS;       //纳秒
    

    4.2 实现方式

  7. 实现Runnable接口

  8. 实现Run方法
  9. 构造ThreadPoolExecutor对象
  10. 调用ThreadPoolExecutor的对象的execute()方法 ,将实现Runnable的对象当做参数传入

    4.3 代码示例

    ```java /**

    • @author zongzhaojin
    • @date 2022/4/16 11:31 */ public class ThreadPool { public static void main(String[] args) throws InterruptedException { int corePoolSize = 5; int maximumPoolSize = 10; int keepAliveTime = 10; TimeUnit timeUnit = TimeUnit.SECONDS; ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(100); ThreadFactory threadFactory = Executors.defaultThreadFactory(); RejectedExecutionHandler defaultHandler = new ThreadPoolExecutor.AbortPolicy(); // 3 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, timeUnit, arrayBlockingQueue, threadFactory, defaultHandler); for(int i = 0;i<1000;i++){ // Thread.sleep(10);

         // 4
         threadPoolExecutor.execute(new RunnableDemo(i));
      

      }

      } } // 1 class RunnableDemo implements Runnable { int num; public RunnableDemo(int num){ this.num = num; } // 2 @Override public void run() { System.out.println(“第”+num+”次: “+Thread.currentThread().getName()+”: hello ThreadPool”); } }

```