zoukankan      html  css  js  c++  java
  • 多线程第二天

    一、线程的六种状态

      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);
                    }
                });
            }
        }
    
  • 相关阅读:
    一些你可能用到的代码
    iOS 键盘下去的方法
    iOS设计模式汇总
    随笔
    Spring cloud config 分布式配置中心 (三) 总结
    Spring cloud config 分布式配置中心(二) 客户端
    Spring cloud config 分布式配置中心(一) 服务端
    jdbcUrl is required with driverClassName spring boot 2.0版本
    JpaRepository接口找不到 spring boot 项目
    解决IntelliJ “Initialization failed for 'https://start.spring.io'
  • 原文地址:https://www.cnblogs.com/fbbg/p/14514552.html
Copyright © 2011-2022 走看看