2021-09-27

juc

什么是JUC:java.util.concurrent包名的简写,是关于并发编程的API。
与JUC相关的有三个包:java.util.concurrent、java.util.concurrent.atomic、java.util.concurrent.locks。

入门程序 卖票

synchronized版本

如何理解买票小程序,其实就是线程操作资源类,资源就是票,多个线程操作该资源时,就会产生线程不安全问题,如何解决,那就是加锁。

卖票不安全版本

代码如下(示例):

package com.atguigu.controller;

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

public class saleTickte {

    public static void main(String[] args) {
        Ticket1 ticket = new Ticket1();
        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        }, "a").start();
        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        }, "b").start();
        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        }, "c").start();

    }
}


/**
 * 票实体类
 */
class Ticket1 {
    private int num = 40;
    public void sale() {
        if (num > 0) {
            try {
                TimeUnit.MILLISECONDS.sleep(30);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "卖出第" + num-- + "张票" + "  还剩" + num + "张");
        }
    }
}

执行结果如下
在这里插入图片描述

synchronized版本

代码如下(示例):

package com.atguigu.controller;

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

public class saleTickte {

    public static void main(String[] args) {
        Ticket1 ticket = new Ticket1();
        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        }, "a").start();
        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        }, "b").start();
        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        }, "c").start();

    }
}
/**
 * 票实体类
 */
class Ticket1 {
    private int num = 15;
    public synchronized void sale() {
        if (num > 0) {
            System.out.println(Thread.currentThread().getName() + "卖出第" + num-- + "张票" + "  还剩" + num + "张");
        }
    }
}

执行结果
在这里插入图片描述

lock版本

package com.atguigu.controller;

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

public class saleTickte {

    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        }, "a").start();
        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        }, "b").start();
        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        }, "c").start();

    }
}

/**
 *
 */
class Ticket {
    private int num = 40;
    /**
     * 买票 
     */
    Lock lock = new ReentrantLock();

    public void sale() {
        lock.lock();
        try {
            if (num > 0) {
                System.out.println(Thread.currentThread().getName() + "卖出第" + num-- + "张票" + "  还剩" + num + "张");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}

执行结果
在这里插入图片描述

那synchronized 和Lock的区别有哪些?
1.Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问;
2.Lock和synchronized有一点非常大的不同,采用synchronized不需要用户去手动释放锁,当synchronized方法或者synchronized代码块执行完之后,系统会自动让线程释放对锁的占用;而Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象

生产者消费者问题

现在需求如下 生产者生产一个 消费者消费一个 有序进行

synchronized版本

package com.atguigu.controller;

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

public class threadDemo {


    public static void main(String[] args) {
        Con1 c = new Con1();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                c.add();
            }, "a").start();
        }


        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                c.decre();
            }, "b").start();
        }
    }


}

/**
 * 资源类
 */
class Con1 {
    private int num = 0;

    /**
     * 新增操作 也就是生产
     */
    public synchronized void add() {
        ///判断  此处很多人都会写成if 写if是不对的 程序会出问题虚假唤醒
        while (num != 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //干活
        num++;
        System.out.println(Thread.currentThread().getName() + "新增到" + num);
        //通知
        this.notifyAll();
    }

    /**
     * 减少操作  相当于消费
     */
    public synchronized void decre() {
        //判断  此处很多人都会写成if 写if是不对的 程序会出问题虚假唤醒
        while (num == 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //干活
        num--;
        System.out.println(Thread.currentThread().getName() + "减少到" + num);
        //通知
        this.notifyAll();
    }
}

执行结果如下 交替运行 线程安全
在这里插入图片描述

Lock版本

package com.atguigu.controller;

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

public class threadDemo {


    public static void main(String[] args) {
        Con2 c = new Con2();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                c.add();
            }, "a").start();
        }


        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                c.decre();
            }, "b").start();
        }
    }


}

/**
 * 资源类
 */
class Con2 {
    private int num = 0;
    Lock lock = new ReentrantLock();
    Condition c = lock.newCondition();

    public void add() {
        lock.lock();
        try {
            //判断  此处很多人都会写成if 写if是不对的 程序会出问题虚假唤醒
            while (num != 0) {
                c.await();
            }
            //干活
            num++;
            System.out.println(Thread.currentThread().getName() + "新增到" + num);
            //通知
            c.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }


    public void decre() {
        lock.lock();
        try {
            //判断  此处很多人都会写成if 写if是不对的 程序会出问题虚假唤醒
            while (num == 0) {
                c.await();
            }
            //干活
            num--;
            System.out.println(Thread.currentThread().getName() + "减少到" + num);
            //通知
            c.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

执行如下
在这里插入图片描述

注意
在高内聚 低耦合的前提下 线程操纵资源类 判断 干活 通知 防止虚假唤醒
如何理解上面这句话 高内聚 低耦合就是所有的方法都是资源类提供 ,我们只需要调用就行
判断 干活 通知 ,如上面这个程序 判断 就是我什么时候进行新增操作,什么时候进行减少操作, 干活 就是 新增 (num++) 减少 (num–) ,通知 就是我们新增好了 需要通知其他线程告诉他们我们新增好了 你快来消费 对应的就是notifyAll();
防止虚假唤醒 这个在程序中 判断哪一步 很多人都会写成if 写成if就会造成虚假唤醒 程序会出问题
所有的生产者消费者模式都可以按照 判断 干活 通知 来做

虚假唤醒 在jdk中的说明 那总结一句就是要使用wait()时不能使用if 要用while
在这里插入图片描述

精准通知

需求如下 调用打印方法 执行顺序不能变 要求先执行打印5次的 在调用打印10次的 在调用打印15次的
分析:在调用打印5次的方法时候 我们不能全部唤醒其他线程,我们需要唤醒的是打印10次的那个线程,在打印10次的方法里面我们需要做的是唤醒打印5次的那个线程
那么在多个线程的操作下 我们如何确保线程 安全 以及做到线程之间的精准通知呢

package com.atguigu.controller;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;

public class EightLock {

    public static void main(String[] args) throws InterruptedException, ExecutionException {

        Prinlt p = new Prinlt();
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                p.priint5();
            }, "a").start();
        }
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                p.priint10();
            }, "b").start();
        }
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                p.priint15();
            }, "c").start();
        }
    }
}
//打印实体类
class Prinlt {
    //这是一个标记 当flag=1 打印5  flag=2 打印10  flag=3 打印15
    private int flag = 1;
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    Condition condition1 = lock.newCondition();
    Condition condition2 = lock.newCondition();

    public void priint5() {
        lock.lock();
        try {
            while (flag != 1) {
                condition.await();
            }
            for (int i = 1; i <= 5; i++) {
                System.out.println(Thread.currentThread().getName() + "   打印" + i + "次");
            }
            flag = 2;
            //唤醒
            condition1.signal();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void priint10() {
        lock.lock();
        try {
            while (flag != 2) {
                condition1.await();
            }
            for (int i = 1; i <= 10; i++) {
                System.out.println(Thread.currentThread().getName() + "   打印" + i + "次");
            }
            flag = 3;
            condition2.signal();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }


    public void priint15() {
        lock.lock();
        try {
            while (flag != 3) {
                condition2.await();
            }
            for (int i = 1; i <= 15; i++) {
                System.out.println(Thread.currentThread().getName() + "   打印" + i + "次");
            }
            flag = 1;
            condition.signal();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

执行结果如下 图未截取完整
在这里插入图片描述

总结 在synchronized 里面等待 唤醒用的方法是 wait() notify() notifyAll() 在lock里面用的是 等待 唤醒用的是 await() signal() signalAll 并且lock功能更加强大 支持精准唤醒

集合类不安全

在工作中用到List,大家可能都会用 List list = new ArrayList();但是呢ArrayList是线程不安全的,那么我们该怎么解决呢?

ArrayList 不安全演示

package com.atguigu.thread;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * Exception in thread "a" java.util.ConcurrentModificationException 并发修改异常
 * 解决办法 1 List<String> list = new Vector<>();
 */
public class ArrayListDemo {


    public static void main(String[] args) {
        //List<String> list = new CopyOnWriteArrayList<>();
        List list = new ArrayList();
        for (int i = 1; i <= 3; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }
    }
}

线程不安全在这里插入图片描述
解决办法 创建CopyOnWriteArrayList集合

package com.atguigu.thread;

        import java.util.*;
        import java.util.concurrent.ConcurrentHashMap;
        import java.util.concurrent.CopyOnWriteArrayList;
        import java.util.concurrent.CopyOnWriteArraySet;

/**
 * Exception in thread "a" java.util.ConcurrentModificationException 并发修改异常
 * 解决办法 1 List<String> list = new Vector<>();
 */
public class ArrayListDemo {


    public static void main(String[] args) {
        /**
         * set 集合也不安全 解决办法
         * Set set = new CopyOnWriteArraySet();
         * Collections.synchronizedSet(new HashSet<>());
         *
         * Map也不安全  解决办法
         * Map map = new ConcurrentHashMap();
         */
        List<String> list = new CopyOnWriteArrayList<>();
        for (int i = 1; i <= 3; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }
    }


}

juc辅助类

package com.atguigu.controller;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;

public class EightLock {


    public static void main(String[] args) throws InterruptedException, ExecutionException {


        /**
         * CountDownLatch 辅助类  该怎么理解这个类呢 做减法  案例当所有离开教室 班长才能离开教室
         * 如果不用FutureTask 很有可能出现线程不安全问题 人还没走完 班长就离开教室了
         */
        CountDownLatch countDownLatch = new CountDownLatch(7);
        for (int i = 0; i < 7; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "离开教室");
                countDownLatch.countDown();
            }, String.valueOf(i)).start();
        }
        countDownLatch.await();
        System.out.println("班长离开教室");



        /**
         * Semaphore 辅助类  案例停车位 new Semaphore(3) 表示有3个停车位
         * 停车位案例
         * new Semaphore(3) 代表有3个车位
         * for (int i = 0; i < 6; i++) 6代表有6个用户来停车
         */
        Semaphore semaphore = new Semaphore(3);
        for (int i = 0; i < 6; i++) {
            new Thread(() -> {
                try {
                    //代表已经使用了一个
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "进入车位");
                    TimeUnit.SECONDS.sleep(3);
                    System.out.println(Thread.currentThread().getName() + "离开车位");

                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    //代表离开之后又有车位了
                    semaphore.release();
                }

            }, String.valueOf(i)).start();
        }
    }
}

辅助类 读写锁 ReadWriteLock 多人同时读 写入只能有一个人写

class Maps {
    ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    Map<String, Object> map = new HashMap();

    public void putToMap(String key, String value) {
        readWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "开始写入");
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "写入完成");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.writeLock().unlock();
        }

    }

    public void getToMap(String key) {
        readWriteLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "读取开始");
            System.out.println(Thread.currentThread().getName() + "读取成功" + "结果为" + map.get(key));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.readLock().lock();
        }
    }
}

package com.atguigu.controller;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.*;

public class EightLock {


    public static void main(String[] args) throws InterruptedException, ExecutionException {
        Maps maps = new Maps();
        for (int i = 1; i <= 3; i++) {
            int finalI = i;
            new Thread(() -> {
                maps.putToMap(finalI + "", finalI + "");
            }, String.valueOf(i)).start();
        }

        for (int i = 1; i <= 3; i++) {
            int finalI = i;
            new Thread(() -> {
                maps.getToMap(finalI + "");
            }, String.valueOf(i)).start();
        }
    }
}

如何实现多线程

除了以前实现Runnable 接口 继承Thread类 我们还有其他方法吗?

实现Callable接口

class future implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        System.out.println("come in callable");
        return 1024;
    }
}

如上 我们如何调用这个call方法呢?

package com.atguigu.controller;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;

public class EightLock {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        FutureTask futureTask = new FutureTask(new future());
        new Thread(futureTask).start();
        System.out.println(futureTask.get());
    }
}

执行结果如下
在这里插入图片描述

FutureTask 是什么?为什么要用这个类;首先Rannable和callable接口并没有直接联系 那么如何让他们产生联系呢 ?
在这里插入图片描述
如上图 FutureTask 实现了Runnable 接口 ,且构造函数可以传一个callable,这就让Runnable 和callable产生了联系,所以new Thread(futureTask).start();就可以直接调用成功;

通过线程池创建

在这里插入图片描述

创建指定数量的线程池
package com.atguigu.controller;

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

public class ThreadPool {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        try {
            for (int i = 1; i <= 9; i++) {
                executorService.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "    执行");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭线程池
            executorService.shutdown();
        }
    }
}

执行结果 始终就3个线程在服务
在这里插入图片描述

创建一个线程的线程池
package com.atguigu.controller;

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

public class ThreadPool {

    public static void main(String[] args) {
        //ExecutorService executorService = Executors.newFixedThreadPool(3);
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        try {
            for (int i = 1; i <= 9; i++) {
                executorService.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "    执行");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭线程池
            executorService.shutdown();
        }
    }
}

执行结果如下 始终只有一个线程在服务
在这里插入图片描述

创建一个自适应的线程池(根据访问的数量 自己会产生合适的线程数)
package com.atguigu.controller;

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

public class ThreadPool {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        try {
            for (int i = 1; i <= 9; i++) {
                executorService.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "    执行");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭线程池
            executorService.shutdown();
        }
    }
}

执行结果如下 根据访问数量 自己会产生合适的线程数
在这里插入图片描述

在上面的几个案例中查看底层可以发现 他们创建线程池的底层其实都用的是同一个类 ThreadPoolExecutor;所以在实际开发中我们一般都会通过ThreadPoolExecutor自定义线程池

ThreadPoolExecutor的七大参数
 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

如上图 这是ThreadPoolExecutor的底源码 我们发现有七个参数 那这七个参数的作用是啥呢?
corePoolSize – 要保留在池中的线​​程数,即使它们处于空闲状态,除非设置了allowCoreThreadTimeOut
maximumPoolSize – 池中允许的最大线程数
keepAliveTime – 当线程数大于核心数时,这是多余空闲线程在终止前等待新任务的最长时间。
unit – keepAliveTime参数的时间单位
workQueue – 用于在执行任务之前保存任务的队列。 这个队列将只保存execute方法提交的Runnable任务。
threadFactory – 执行程序创建新线程时使用的工厂
handler – 执行被阻塞时使用的处理程序,因为达到了线程边界和队列容量:

我们以一家银行来举例
银行就代表线程池 那么银行一共有5个窗口提供服务 这5个窗口就是maximumPoolSize (池中允许的最大线程数) 但是今天是周天 业务比较少 只开放了2个窗口提供服务,这2个窗口就是corePoolSize (核心线程数), 但是突然间来了五个人 这时只有两个窗口在服务,显然不够用,这时就需要让那3个人在候客区等待,这个候客区就是workQueue(阻塞队列),假如候客区最多容纳3个人,此时又来了3个人,这个时候候客区已经装不下了,那么此时就需要开放另外3个窗口来提供服务,当所有人的业务都办理完了,这个时候很明显开放的3个窗口是在浪费资源,我们可以设定一个时间,过了多长时间3个窗口就关闭,此时 keepAliveTime 就是这个道理,(unit 代表单位) keepAliveTime设定的时间过了之后,那么这三个窗口就关闭,也就代表三个线程关闭,threadFactory就是线程池工厂,用来产生线程的,这个一般默认即可,RejectedExecutionHandler 这个代表拒绝策略,该怎么理解,比如说银行出了一个理财产品,来的人特别多,所有窗口都开放 候客区也坐满了,那么后面的人我们就不在接纳,告诉他们让他们区别的银行办理

ThreadPoolExecutor的四种拒绝策略

1.默认拒绝策略 AbortPolicy 只要超过最大的服务数量立马抛异常

package com.atguigu.controller;

import java.util.concurrent.*;

public class ThreadPool {

    public static void main(String[] args) {
        //自定义线程池
        ThreadPoolExecutor executorService = new ThreadPoolExecutor(2,
                5,
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
        try {
            for (int i = 1; i <= 9; i++) {
                executorService.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "    执行");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭线程池
            executorService.shutdown();
        }
    }
}

如图 当最大线程数是5 阻塞队列最大值为3 那么最大接待的访问数是8 当有9个来访问时 就会抛异常
这就是默认的拒绝策略
在这里插入图片描述
2. CallerRunsPolicy拒绝策略 该策略既不会抛弃任务 也不会抛异常 谁创建了该任务 谁来执行

package com.atguigu.controller;
import java.util.concurrent.*;
public class ThreadPool {
    public static void main(String[] args) {
        ThreadPoolExecutor executorService = new ThreadPoolExecutor(2,
                5,
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());
        try {
            for (int i = 1; i <= 9; i++) {
                executorService.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "    执行");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭线程池
            executorService.shutdown();
        }
    }
}

执行结果如下 第九个任务由main方法执行了
在这里插入图片描述

3 DiscardPolicy 该策略会默默的丢弃无法处理的任务 不做任何处理 也不报错 如果允许任务丢失 这是最好的一种策略

package com.atguigu.controller;

import java.util.concurrent.*;

public class ThreadPool {

    public static void main(String[] args) {
        ThreadPoolExecutor executorService = new ThreadPoolExecutor(2,
                5,
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardPolicy());
        try {
            for (int i = 1; i <= 9; i++) {
                executorService.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "    执行");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭线程池
            executorService.shutdown();
        }
    }
}

执行结果如下 不报错 但是只执行了8个任务
在这里插入图片描述

4 DiscardOldestPolicy 该策略抛弃队列中等待最久的任务 然后把当前任务加入到队列中 尝试再次提交当前任务

package com.atguigu.controller;

import java.util.concurrent.*;

public class ThreadPool {

    public static void main(String[] args) {
        ThreadPoolExecutor executorService = new ThreadPoolExecutor(2,
                5,
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardOldestPolicy());
        try {
            for (int i = 1; i <= 9; i++) {
                executorService.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "    执行");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭线程池
            executorService.shutdown();
        }
    }
}

执行结果如下
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值