多线程第二天

一、线程的六种状态

  1、new   创建线程

  2、Runnable(执行状态)  java中将线程的就绪(Ready)和运行中(running)中统称为执行状态,此时的线程获取了cup的执行权

  3、Blocked(线程阻塞)   线程此时具有争夺cup执行权的条件,但是还没有抢到时间片。正在运行的线程通过wait()或者sleep()可以到Blocked状态。

  4、Wait(无限等待)   正在执行的线程可通过wait()进入该状态,相当于线程休眠的状态,但是自己无法苏醒,需要其他线程通过notify()或者notifyall()来唤醒该线程,唤醒后的状态时线程阻塞态。

  5、TimeWait(计时等待)   可以通过sleep()或者wait()加时间参数来进入该状态,在计时期满或者收到了唤醒时,线程转换为线程阻塞态,等待获取cup的执行权

  6、Teminated(终止)  当线程正常执行run方法结束后,或者收到没有捕获的异常,都会导致线程终止

二、线程通信

2.1线程通信概述

  概念:当多个线程共同完成一个任务,但是处理的动作却不相同。

  为什么要线程通信?

    当需要多个线程公共去执行一个任务时,需要让线程有序的执行,线程之间就需要通信机制。

  实现线程通信的机制?

    等待唤醒机制。

2.2等待唤醒机制 

  等待唤醒机制是一种线程协作的机制。

  一个线程在进行了规定的操作后,进入到了wait状态。等待其他线程执行完指定的代码后,通过notify将wait状态的线程唤醒,如果有多个wait的线程,可以通过notifyall将所有的等待线程唤醒。

  等待唤醒机制的方法:

    wait():将线程变为等待状态。

    notify():唤醒等待状态的线程,变成阻塞态,如果能直接获取线程锁,就直接变成可运行态。

    notifyAll():唤醒所有等待状态的线程。

  调用等待唤醒机制方法应该注意的细节:

    (1)wait()和notify()方法要通过同一个锁对象调用

    (2)wait()和notify()方法都属于object类

    (3)wait()和notify()要在同步代码、同步方法,因为必须通过锁调用这些方法。

2.3生产者和消费者问题

  生产者和消费者问题是经典的等待唤醒机制问题。

场景模拟:两个线程共同实现一个交互的任务逻辑

  饺子馆:

    食客线程:向老板点了一份饺子,如果有饺子,食客就开始吃饺子,吃完后将饺子的改为false。并唤醒老板线程。如果没有饺子,食客线程进入等待。

    老板线程:如果现在有饺子,老板线程等待。如果没有饺子,老板线程做饺子,做好后改变饺子的状态,并唤醒食客的线程。

    饺子状态:有true,无false

 三、线程池

  1、什么是线程池?

    就是一个容纳多个线程的容器,其中的线程可以反复使用,避免了反复创建销毁线程的过程

  2、为什么需要线程池?

    我们需要线程时,需要创建线程,线程用完后需要销毁线程。线程的创建和销毁都需要耗费时间。如果有大量的创建和销毁的过程,就会浪费大量的系统资源。

  3、使用线程池的好处?

    1、节省系统资源  2、加快响应速度      3、方便管理线程

  4、怎么创建线程池?

    java官方提供了java.util.concurrent.executor包,但是它并不是一个线程池,而是一个执行线程的工具,真正的线程池是java.util.concurrent.executorService,线程是很难配置的,尤其是对于线程池的原理不是很清楚的情况下,很有可能配置的线程池不是较优 的,因此在 java.util.concurrent.Executors 线程工厂类里面提供了一些静态工厂,生成一些常用的线程池。官方建议使用Executors工程类来创建线程池对象。

  5、创建线程池的四种方式

    5.1 newCachedThreadPool(缓存线程池)

      特点:会根据需要创建新的线程,线程池中的线程可以复用,当线程不够会创建新的线程

        该线程通常用在任务耗时短的业务

        如有线程超过一分钟未使用,就会被回收

        使用execute()可以来重复使用池的线程

public static void main(String[] args) {
        ExecutorService es = Executors.newCachedThreadPool();
        for(int i=0;i<20;i++){
            final int index=i;
            es.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"---"+index);
                }
            });
        }
    }

     5.2 newFixedThreadPool(int ThreadCount)    定容缓冲池

      特点:缓冲池有初始容量,池中的线程可以反复使用

         如果线程池中没有空闲的线程,那么请求等待

         如果有线程被终止,线程池中会再创建一个新的线程

         线程池中的线程不会自己回收,除非调用显示shutdown方法

 public static void main(String[] args) {
        ExecutorService es = Executors.newFixedThreadPool(20);
        for (int i=0;i<100;i++){
            final int index=i;
            es.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"----"+index);
                }
            });
        }
    }

   5.3newScheduledThreadPool()定时缓冲池

    特点:支持定时和循环任务执行

       延迟定时,延迟的时间间隔使用调用开始,并不受线程运行时间长短的影响

public static void main(String[] args) {
        ScheduledExecutorService se = Executors.newScheduledThreadPool(3);
        for(int i= 0;i<200;i++){
            final int index = i;
            se.schedule(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"--->"+index);
                }
            },5, TimeUnit.SECONDS);
        }
    }

   5.4 newSingleThreadExecutor() 单一线程池

    特点:最多只开启一个线程,对于队列中的Runnable,挨个执行

public static void main(String[] args) {
        ExecutorService es = Executors.newSingleThreadExecutor();
        for(int i= 0;i<200;i++){
            final int index = i;
            es.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"--->"+index);
                }
            });
        }
    }

 

posted @ 2021-03-12 21:21  橙汁one  阅读(55)  评论(0编辑  收藏  举报