线程池原理和应用

线程模型

线程池

在这里插入图片描述

线程池状态:

在这里插入图片描述

线程池运行任务

在这里插入图片描述
juc
别人的知识库
csdn-juc
笔记-juc
juc3

cancel

线程的状态和创建

线程的状态
由Thread类总定义的枚举定义了6个状态
Thread.sleep();//线程暂停,不释放锁
Object.wait();//线程定时(到时醒),无限等待,释放锁,通过notify() /notifyAll() 唤醒

线程的创建方式

1/继承

public class MyThread extends Thread {
    //继承Thread从写run方法
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
        System.out.println("开启了新的而线程");
    }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
        System.out.println(Thread.currentThread().getName());
    }
}

2/实现

   public static void createThread(){
        Thread thread = new Thread(() -> {
            System.out.println("开启的线程");
            System.out.println(Thread.currentThread().getName());
        });
        thread.start();
    }

3/callable

4/线程池

/**
创建后默认:有corePoolSize个线程。
*/
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler);

参数解析:
corePoolSize(必需):核心线程数。默认情况下,核心线程会一直存活,但是当将 allowCoreThreadTimeout 设置为 true 时,核心线程也会超时回收。
maximumPoolSize(必需):线程池所能容纳的最大线程数。当活跃线程数达到该数值后,后续的新任务将会阻塞。
keepAliveTime(必需):线程闲置超时时长。如果超过该时长,非核心线程就会被回收。如果将 allowCoreThreadTimeout 设置为 true 时,核心线程也会超时回收。
unit(必需):指定 keepAliveTime 参数的时间单位。常用的有:TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)、TimeUnit.MINUTES(分)。

workQueue(必需):任务队列。通过线程池的 execute() 方法提交的 Runnable 对象将存储在该参数中。其采用阻塞队列实现。
threadFactory(可选):线程工厂。用于指定为线程池创建新线程的方式。
handler(可选):拒绝策略。当达到最大线程数时需要执行的饱和策略。
    
4.1 任务队列(workQueue)
任务队列是基于阻塞队列实现的,即采用生产者消费者模式,在 Java 中需要实现 BlockingQueue 接口。但 Java 已经为我们提供了 7 种阻塞队列的实现:

ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列(数组结构可配合指针实现一个环形队列)。
LinkedBlockingQueue: 一个由链表结构组成的有界阻塞队列,在未指明容量时,容量默认为 Integer.MAX_VALUE。
PriorityBlockingQueue: 一个支持优先级排序的无界阻塞队列,对元素没有要求,可以实现 Comparable 接口也可以提供 Comparator 来对队列中的元素进行比较。跟时间没有任何关系,仅仅是按照优先级取任务。
DelayQueue:类似于PriorityBlockingQueue,是二叉堆实现的无界优先级阻塞队列。要求元素都实现 Delayed 接口,通过执行时延从队列中提取任务,时间没到任务取不出来。
SynchronousQueue: 一个不存储元素的阻塞队列,消费者线程调用 take() 方法的时候就会发生阻塞,直到有一个生产者线程生产了一个元素,消费者线程就可以拿到这个元素并返回;生产者线程调用 put() 方法的时候也会发生阻塞,直到有一个消费者线程消费了一个元素,生产者才会返回。
LinkedBlockingDeque: 使用双向队列实现的有界双端阻塞队列。双端意味着可以像普通队列一样 FIFO(先进先出),也可以像栈一样 FILO(先进后出)。
LinkedTransferQueue: 它是ConcurrentLinkedQueueLinkedBlockingQueueSynchronousQueue 的结合体,但是把它用在 ThreadPoolExecutor 中,和 LinkedBlockingQueue 行为一致,但是是无界的阻塞队列。
注意有界队列和无界队列的区别:如果使用有界队列,当队列饱和时并超过最大线程数时就会执行拒绝策略;而如果使用无界队列,因为任务队列永远都可以添加任务,所以设置 maximumPoolSize 没有任何意义。


4.2拒绝策略
        //Executors.defaultThreadFactory() --juc默认实现的线程工厂,new MyThreadFactory()-自己实现的线程工厂
        //拒绝策略:CallerRunsPolicy 满了后由调用者执行
        //AbortPolicy - 抛出异常,中止任务。抛出拒绝执行 RejectedExecutionException 异常信息。线程池默认的拒绝策略。必须处理好抛出的异常,否则会打断当前的执行流程,影响后续的任务执行
        //CallerRunsPolicy - 使用调用线程执行任务。当触发拒绝策略,只要线程池没有关闭的话,则使用调用线程直接运行任务。一般并发比较小,性能要求不高,不允许失败。但是,由于调用者自己运行任务,如果任务提交速度过快,可能导致程序阻塞,性能效率上必然的损失较大
        //DiscardPolicy - 直接丢弃,其他啥都没有
        //DiscardOldestPolicy - 丢弃队列最老任务,添加新任务。当触发拒绝策略,只要线程池没有关闭的话,丢弃阻塞队列 workQueue 中最老的一个任务,并将新任务加入

    
    

/**
案例:线程池执行完所有的任务后关闭线程池
    */
package com.baseNote.jucdemo.createthread;

import java.util.concurrent.*;

public class ExcutorDemo {
    public static void main(String[] args) {
        //线程池
        //Executors.newCachedThreadPool();
        //ExecutorService;
        //Executor;
        //队列

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 2, 10, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(1),
                Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());

        //Executors.defaultThreadFactory() --juc默认实现的线程工厂,new MyThreadFactory()-自己实现的线程工厂
        //拒绝策略:CallerRunsPolicy 满了后由调用者执行
        //AbortPolicy - 抛出异常,中止任务。抛出拒绝执行 RejectedExecutionException 异常信息。线程池默认的拒绝策略。必须处理好抛出的异常,否则会打断当前的执行流程,影响后续的任务执行
        //CallerRunsPolicy - 使用调用线程执行任务。当触发拒绝策略,只要线程池没有关闭的话,则使用调用线程直接运行任务。一般并发比较小,性能要求不高,不允许失败。但是,由于调用者自己运行任务,如果任务提交速度过快,可能导致程序阻塞,性能效率上必然的损失较大
        //DiscardPolicy - 直接丢弃,其他啥都没有
        //DiscardOldestPolicy - 丢弃队列最老任务,添加新任务。当触发拒绝策略,只要线程池没有关闭的话,丢弃阻塞队列 workQueue 中最老的一个任务,并将新任务加入

        for (int i = 0; i < 10; i++) {
            threadPoolExecutor.execute(()->{
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

                System.out.println("线程执行了方法-->xxx---"+Thread.currentThread().getName());
            });
        }
        threadPoolExecutor.shutdown();
        System.out.println("主线程结束"+Thread.currentThread().getName());
    }
}



工具类:Executors

线程安全-锁

统一把锁
同一个共享资源
同一个操作方法
才能控制--线程安全问题

synchronized

  /**
     * synchronized 同步代码块的参数-对象锁 -原理
     * 每个对象的锁-锁代码块(操作共享资源)
     * 默认的所有3中:
     *  同步代码块-自定义锁对象,
     *  静态同步方法-Obj.class对象,
     *  非静态代码块-this对象
     *
     *  共享资源加锁策略--->一个资源仅能有一个锁
     */
package com.baseNote.jucdemo.createthread;

import java.util.concurrent.TimeUnit;

public class DemoTest {
    private static String lockObj = "a";
    /**
     * 用三个锁-来锁这个共享资源-是有线程安全问题的
     */
    private static int num = 30;
    public static void main(String[] args) {
        DemoTest demoTest = new DemoTest();
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                demoTest.custLock();
            });
            thread.start();
        }
    }

    /**
     * synchronized 同步代码块的参数-对象锁 -原理
     * 每个对象的锁-锁代码块(操作共享资源)
     * 默认的所有3中:
     *  同步代码块-自定义锁对象,
     *  静态同步方法-Obj.class对象,
     *  非静态代码块-this对象
     *
     *  共享资源加锁策略--->一个资源仅能有一个锁
     */
    public void custLock(){
        synchronized (lockObj){
//            System.out.println("自定义锁-->线程获取锁:"+Thread.currentThread().getName());
            try {
                TimeUnit.MILLISECONDS.sleep(10);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            num--;
            System.out.println(num);
             objLock();
             classLock();
        }
    }

    /**
     * 锁-this
     */
    public synchronized void  objLock(){
            try {
                TimeUnit.MILLISECONDS.sleep(10);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            num--;
//        System.out.println("对象锁-->"+Thread.currentThread().getName() +"共享资源"+num);
        System.out.println(num);
    }

    /**
     * 锁-this
     */
    public  static synchronized void  classLock(){
        try {
            TimeUnit.MILLISECONDS.sleep(10);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        num--;
//        System.out.println("静态锁-->"+Thread.currentThread().getName() +"共享资源"+num);
        System.out.println(num);
    }
}

Lock锁


```java
package com.baseNote.jucdemo.createthread;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 同一把锁
 * 同一个共享资源
 * 同一个操作方法对象
 */
public class LockDemo {
    private static int num = 300;

    /**
     * Lock锁
     */
    private static Lock lock = new ReentrantLock();

    public static void main(String[] args) {
        for (int i = 0; i < 300; i++) {
            Thread thread = new Thread(() -> {
                //多线程调用同一个对象
                sword();
            });
            thread.start();
        }

    }

    public static void sword() {
        lock.lock();
        num--;
        lock.unlock();
        System.out.println(num);
    }

}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值