• 多线程第二天


    一、线程的六种状态

      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);
                    }
                });
            }
        }
    
  • 相关阅读:
    关于多态的一些问题
    003 关于shell基础,大数据的前期准备
    002 在大数据中基础的llinux基本命令
    013 MapReduce八股文的wordcount应用
    接口里语句的修饰问题
    Apache Rewrite url重定向功能的简单配置
    学习笔记 --- 缓存、动态页面静态化、网站优化
    使用PHP连接、操纵Memcached的原理和教程
    Apache中关于页面缓存的设置
    缓存(之一) 使用Apache Httpd实现http缓存
  • 原文地址:https://www.cnblogs.com/fbbg/p/14514552.html
Copyright © 2020-2023  润新知