wait、notifly详细教程及线程池理解

多线程在什么场景下需要使用,及其设置corePool线程池大小多大,配置什么补偿策略,

为什么要是用线程池?

线程是操作系统能够运行调度的最小单位。

当应用场景为,计算密集型时:为了将每个cpu充分利用起来,线程数量正常是cpu核数+1,还可以看jdk的使用版本,1.8版本中可以使用cpu核数*2。

当应用场景为,io密集型时:做web端开发的时候,涉及到大量的网络传输,不进入持,缓存和与数据库交互也会存在大量io,当发生io时候,线程就会停止,等待io结束,数据准备好,线程才会继续执行,所以当io密集时,可以多创建点线程,让线程等待时候,其他线程执行,更高效的利用cpu效率,他有一个计算公式,套用公式的话,双核cpu理想的线程数就是20。

普通线程需要频繁的创建,执行,销毁三步,线程池的作用能大大减少创建和销毁,使线程在执行的时候不调用创建和销毁,提高线程执行效率,合理的设置线程数,复用线程,避免频繁回收和创建,提高系统运行速率和吞吐量。

 

线程的核心字段:corePoolSize核心线程数,maxPoolSize最大线程数,QueueCapacity队列大小,keepAliveSecond线程最大空闲时间。

threadNamePrefix设置线程名字。

 

线程的常用监控状态:

ThreadPoolExecutor :

活跃线程数:activeCount  线程总数:poolSize   需要执行的任务数:taskCount

已完成任务数:compatedTaskCount  曾经创建过最大的线程数:largePoolSize

 

继承ThreadPoolExcutor:可以重写线程的生命周期函数,afterExecutor,beforeExecutor,执行任务前调用,执行任务后调用,退出任务调用。

 

线程池的处理流程:

  1. 提交任务到线程池,查看核心线程是否都在执行,若没有,则执行当前线程,都在执行的话就2
  2. 查看核心线程数是否满了,若没有满,创建,若满了,执行3
  3. 查看队列大小是否满了,若没有满,放入队列,若满了,执行4
  4. 查看线程池是否满了,没满创建一条线程,满了的话执行相应的拒绝策略。

 

根据实际场景,可以选择合适自己的拒绝策略,设置rejectedExecutionHandler来配置拒绝策略可以实现接口自定义,jdk自带的有四种拒绝策略:

  1. 拒绝处理策略:用于被拒绝的任务将抛出异常。
  2. CallerRunsPolicy:如果有被拒绝的任务,直接在调用者所在的线程调用execute()方法。
  3. DiscardOldestPolicy:如果有被拒绝的任务,选择生命周期存在时间最长的任务放弃。
  4. DiscardPolicy:如果有被拒绝的任务,默认直接放弃此任务。

 

 

实现多线程的方法有哪些?

  1. 可以用类实现runable接口,实例化new Thread(),在括号放入target,调用.start启动。
  2. 可以继承thread类,实例化类调用.start()启动线程。
  3. 可以实现CallAble来重写call方法,前两个是重写run(),此方法可以有返回值,用FatureTask来启动,返回值用result.get()获取。
  4. Jdk1.5之后引入executor框架线程池来实现,解耦了提交和执行线程,用户只需要提交线程,其他什么时候执行,由谁执行,都交给了ExecutorService。

Executors可以创建四个不同的线程池:

单个串行执行Executors.newSingleThreadExecutor:线程出现异常重新创建线程。

固定线程数量线程池Executors.newFixedThreadExecutor:可以指定线程数量。

缓存线程池Executors.newCacheThreadExecutor:可以延迟执行,执行有返回值的任务。

无限制线程池Executors.newScheduleThreadExecutor:大小无限制,适合周期性,定时器。

Executors提交任务有两种方式:

Execute():无返回值。

Submit():有返回值。

停止线程的两种方式:

shutDown():将线程池状态设置为shutDown,停止所有未执行的线程,并将正在执行的线程执行完。

shutDownNow():将线程池状态设置为stop,并尝试停止所有线程,可能会导致线程执行一半停止,未执行完。

 

CountDownLatch():可以使用countDownLatch,countDownLatch数量(线程核心数,任务数),通过构造方法吧数量传到实现runable的线程类里,每次执行线程完毕一次,调用countDown()-1,最后不需要和之前那样调用executorService.shotDown()关闭线程池,调用countDownLatch.wait()方法。

优点:允许一个或多个线程等待直到其他线程完成一组操作的同步辅助。

我的理解是,可以在wait之后写需要执行的代码块,此代码块必定会在等待其他线程执行完之后执行,若不用countDownLatch,此处的代码块可能会在与其他线程同步执行。

wait就是当countDOwnLatch数量为0时才能继续执行。

 

Sleep():不会释放锁,规定时间内阻塞线程。

Wait():释放锁,线程进入等待,将此线程放入线程池中,等待其他线程调用notify() 或者notifyAll()唤醒。

Join():释放锁,因为源代码里包含了wait(),等待线程该线程终止,主线程等待子线程执行完毕。

Yield():不会释放锁,暂停当前线程,让自己同优先级,优先级更高的线程先执行。

注意:wait(),notifyAll,notify()不属于thread类,属于object,因为他们都必须标明所属的锁,而锁又是任意对象,能被任意对象调用的类一定属于Object。

 

本文代码重点:锁的唤醒机制(wait,notifly的使用)。

当功能需要读和写的时候,若数据为空,读的时候则让其等待,等待写的进程写入数据,在将读的进程唤醒。

package com.miu.web.threadCon;

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

public class WaitNotifyThread {

    /*
    * 唤醒等待代码
    *
    * */
    public static void main(String[] args) {
        UserClass userClass = new UserClass();
        InputClass inputClass = new InputClass(userClass);
        OutputClass outputClass = new OutputClass(userClass);
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        executorService.execute(inputClass);
        executorService.execute(outputClass);

        executorService.shutdown();
    }

    static class InputClass implements Runnable{

        private UserClass userClass;

        public  InputClass(UserClass userClass){
            this.userClass=userClass;
        }

        @Override
        public void run() {
            while(true){
                synchronized (userClass){
                    if(userClass.flag){
                        System.out.println("Input等待进入");
                        try{
                            userClass.wait();
                        }catch (Exception e){

                        }
                    }
                    userClass.setName("张三");
                    userClass.setAge("18");
                    UserClass.flag = true;
                    userClass.notify();

                }
            }
        }
    }

    static class OutputClass implements Runnable{

        private UserClass userClass;

        public  OutputClass(UserClass userClass){
            this.userClass=userClass;
        }

        @Override
        public void run() {
            while(true){
                synchronized (userClass){
                    if(!userClass.flag){
                        System.out.println("OutPut等待进入");
                        try{
                            userClass.wait();
                        }catch (Exception e){

                        }
                    }

                    System.out.println("输出:"+userClass.getName()+",age:"+ userClass.getAge());
                    UserClass.flag = false;
                    userClass.notify();
                }
            }
        }
    }

     static class UserClass {
        private String name;

        private String age;

        private static boolean flag = false;

         public String getName() {
             return name;
         }

         public void setName(String name) {
             this.name = name;
         }

         public String getAge() {
             return age;
         }

         public void setAge(String age) {
             this.age = age;
         }
     }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

后端从入门到精通

你的鼓励是我最大的动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值