JUC编程

JUC编程

一 、创建线程

1.实现Runable接口 (没有返回值)

        new Thread(new Runnable() {
            @Override
            public void run() {
                
            }
        },"thread name").start();
    
    //简洁写法
    new Thread(() -> {}, "A").start();

2.实现Callable()接口 (有返回值)

package com.lh.juc;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

class CallableTak implements Callable<Integer>{

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

public class CallableDemo {
    public static void main(String[] args) throws Exception {

        FutureTask task = new FutureTask(new CallableTak());


         new Thread(task, "A").start();

        //获取返回值
        task.get();

    }
}

二. syschronized 锁

1.作用域

  • 作用在实例方法上:锁类的是实例对象
  • 作用在静态方法上:锁住的是类对象
  • 作用在实例对象的代码块:锁住的是实例对象
  • 作用在class对象:锁住的是类对象
  • 任意实例的对象:锁住的是实例对象的Object

​ 能锁 但是锁定粒度太大了 不够灵活`

public synchronized void saleTicket() {
    }
}

三. Locks锁

更加灵活

private Lock lock = new ReentrantLock();
public void saleTicket() 
    //加锁
    lock.lock();
    try {
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        
        //释放锁
        lock.unlock();
    }

}

四、线程之间的通信

1.wait() - Object类的方法

使对象释放共享锁,从运行状态退出,进入等待的队列,直到再一次被唤醒 重新进入竞争锁的状态。

2.notify() - Object类的方法

随机唤醒等待队列中等待同一共享资源的一个线程,并使该线程退出等待队列,进入可运行状态,也就是notify()方法仅通知一个线程。

3.notifyAll() - Object类的方法

使所有正在等待队列中等待同一共享资源的全部线程退出等待队列,进入可运行状态。此时,优先级最高的那个线程最先执行,但也有可能是随机执行,这取决于JVM虚拟机的实现。

4.sleep() - Thread的方法

使线程进入等待状态,但是不会释放对象锁也不会让出CPU,持续保持对该对象的监视状态,指定时间结束后自动唤醒。可以使用interrupt 强行打断。

5. lock.lock() - Lock接口方法

6.await() -Lock CondItion接口的方法 - 对标 wait()

7.signal() -Lock CondItion接口的方法 - 对标 notify()

8.signalAll() -Lock CondItion接口的方法 - 对标 notifyAll()

9.Demo (synchronized 版)

如果没有使用synchronized 或者其他锁 锁住当前对象 也就相当于没有当前线程不是当前对象的占有者 不能使用 wait notifyAll 等方法会抛出 IllegalMonitorStateException 异常

例子1:单生产 单消费 (一个线程生产,一个线程消费)

package com.lh.juc;


/**
 * 线程之间的通信
 * <p>
 * 练习:两个线程操作一个变量 初始值为 分别进行加减 进行十次以后还是0
 * 1.创建资源类 也就是业务逻辑处理类
 * 2。创建线程操作资源类
 */
public class ThreadWaitNotifyDemo {


    public static void main(String[] args) {

        DoSomeThing doSomeThing = new DoSomeThing();


        new Thread(() -> {
            try {

                    doSomeThing.increment();

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "A").start();
        new Thread(() -> {
            try {
                for (int i = 0; i < 9; i++) {
                    doSomeThing.decrement();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "B").start();
    }

}


class DoSomeThing {
    private int num = 0;

    public synchronized void increment() throws InterruptedException {


        //判断
        if (num != 0) {
            this.wait();
        }
        //干活
        num++;
        System.out.println(Thread.currentThread().getName() + ":" + num);

        //通知

        // 如果没有使用synchronized 或者其他锁 锁住当前对象 也就相当于没有当前线程不是当前对象的占有者 不能使用 wait notifyAll 等方法
        // 会抛出 IllegalMonitorStateException 异常

        this.notifyAll();
    }

    public synchronized void decrement() throws InterruptedException {


        //判断
        if (num == 0) {
            //线程进入等待状态 notifyAll 唤醒
            this.wait();
        }
        //干活
        num--;
        System.out.println(Thread.currentThread().getName() + ":" + num);

        //通知
        this.notifyAll();
    }

}

例子2:多生产 多消费

1.存在问题-虚拟唤醒

线程间进行通信(wait、notify…)的场景下不能用if 不能用if 不能用 if 必须用 while

 private int num = 0;

    public synchronized void increment() throws InterruptedException {

        //判断
        if (num != 0) {
     		//假如此时 num=1
            //A1线程在wait()之前中断 
            this.wait();
        }
         //num=1 A1再次唤醒的时候不会再走if A2此时进来的已经完成了+1操作 A1不会重新判断 num!=0 (if判断只会走一次) 
        // A1直接往下num++ =>虚假唤醒s
        num++;
        System.out.println(Thread.currentThread().getName() + ":" + num);

案例:if判断与可能会导致虚假唤醒 因为 if 只会判断一次 此时if 判断里边的 wait在线程第二次唤醒的情况下并不会执行。

2.解决

用while解决 线程被重新唤醒后不会跳过while方法判断往下走。

package com.lh.juc;


/**
 * 线程之间的通信
 * <p>
 * 练习:两个线程操作一个变量 初始值为 分别进行加减 进行十次以后还是0
 * 1.创建资源类 也就是业务逻辑处理类
 * 2。创建线程操作资源类
 */
public class ThreadWaitNotifyDemo {


    public static void main(String[] args) {

        DoSomeThing doSomeThing = new DoSomeThing();


        new Thread(() -> {
            try {
                for (int i = 0; i < 9; i++) {
                    doSomeThing.increment();
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "A").start();
        new Thread(() -> {
            try {
                for (int i = 0; i < 9; i++) {
                    doSomeThing.decrement();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "B").start();


        new Thread(() -> {
            try {
                for (int i = 0; i < 9; i++) {
                    doSomeThing.increment();
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "C").start();
        new Thread(() -> {
            try {
                for (int i = 0; i < 9; i++) {
                    doSomeThing.decrement();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "D").start();
    }

}


class DoSomeThing {
    private int num = 0;

    public synchronized void increment() throws InterruptedException {

        //判断
        while (num != 0) {
            this.wait();
        }
        //干活
        num++;
        System.out.println(Thread.currentThread().getName() + ":" + num);

        //通知

        //   如果没有使用synchronized 或者其他锁 锁住当前对象 也就相当于没有当前线程不是当前对象的占有者 不能使用 wait notifyAll 等方法
        // 会抛出

        this.notifyAll();
    }

    public synchronized void decrement() throws InterruptedException {


        //判断
        while (num == 0) {
            //线程进入等待状态 notifyAll 唤醒
            this.wait();
        }
        //干活
        num--;
        System.out.println(Thread.currentThread().getName() + ":" + num);

        //通知
        this.notifyAll();
    }

}

10.锁现象

1.标准访问

package com.lh.juc;



class Phone{
    public synchronized void sendEmail(){
        System.out.println("send email");
    }

    public synchronized void sendSMS(){
        System.out.println("send SMS");
    }
}

/**
 * 1.标准访问 先打印邮件还是短信 => 不一定啊 线程star后 由CPU来调用 =>先打印邮件 
 */
public class Lock8 {

    public static void main(String[] args) throws Exception {
        Phone phone = new Phone();
        new Thread(phone::sendEmail,"A").start();
        Thread.sleep(200); //保证A先启动
        new Thread(phone::sendSMS,"B").start();

    }


}

2.同一个对象

package com.lh.juc;


import java.util.concurrent.TimeUnit;

class Phone {
    public synchronized void sendEmail() {
        try { TimeUnit.SECONDS.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); }
        System.out.println("send email");
    }

    public synchronized void sendSMS() {
        System.out.println("send SMS");
    }
}

/**
 * <p>
 * 2.邮件方法暂停4秒 先打印邮件还是短信 => 邮件 => 同一个对象使用的是同一个锁的资源 线程会竞争同一把锁 先到的
 */
public class Lock8 {

    public static void main(String[] args) throws Exception {
        Phone phone = new Phone();
        new Thread(phone::sendEmail, "A").start();
        Thread.sleep(200); //保证A先启动
        new Thread(phone::sendSMS, "B").start();

    }


}

3.新增一个普通方法

package com.lh.juc;


import java.util.concurrent.TimeUnit;

class Phone {
    public synchronized void sendEmail() {
        try { TimeUnit.SECONDS.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); }
        System.out.println("send email");
    }

    public synchronized void sendSMS() {
        System.out.println("send SMS");
    }

    public void hello(){
        System.out.println("hello");
    }
}

/**
 * 3.新增一个普通hello()方法 新打印邮件还是 hello() => 普通方法不会竞争锁 会直接执行
 */
public class Lock8 {

    public static void main(String[] args) throws Exception {
        Phone phone = new Phone();
        new Thread(phone::sendEmail, "A").start();
        Thread.sleep(200); //保证A先启动
        new Thread(phone::hello, "B").start();

    }


}

4.创建一个新对象

package com.lh.juc;


import java.util.concurrent.TimeUnit;

class Phone {
    public synchronized void sendEmail() {
        try { TimeUnit.SECONDS.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); }
        System.out.println("send email");
    }

    public synchronized void sendSMS() {
        System.out.println("send SMS");
    }

    public void hello(){
        System.out.println("hello");
    }
}

/**
 * 4.两个Phone对象 phone1 phone2 先打印邮件还是短信 =>先打印SMS => 
 		两个不同的对象使用的锁资源不一样,线程先调度的先执行,没有锁竞争。
 */
public class Lock8 {

    public static void main(String[] args) throws Exception {
        Phone phone = new Phone();
        Phone phone2 = new Phone();
        new Thread(phone::sendEmail, "A").start();
        Thread.sleep(200); //保证A先启动
        new Thread(phone2::sendSMS, "B").start();

    }


}

5.静态方法调用

package com.lh.juc;


import java.util.concurrent.TimeUnit;

class Phone {


    public static synchronized void sendEmail() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("send email");
    }

    public static synchronized void sendSMS() {
        System.out.println("send SMS");
    }

    public void hello() {
        System.out.println("hello");
    }
}

/**
 * 5.两个静态同步方法,,先打印邮件还是短信 => 先打印邮件 => 静态同步方法 都属于类对象 所以是同一把锁 会造成竞争等待
 */
public class Lock8 {

    public static void main(String[] args) throws Exception {
        Phone phone = new Phone();
        Phone phone2 = new Phone();

        new Thread(Phone::sendEmail, "A").start();
        Thread.sleep(200); //保证A先启动
        new Thread(Phone::sendSMS, "B").start();

    }


}

6.一个静态方法 一个普通方法

package com.lh.juc;


import java.util.concurrent.TimeUnit;

class Phone {


    public static synchronized void sendEmail() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("send email");
    }

    public  synchronized void sendSMS() {
        System.out.println("send SMS");
    }

    public void hello() {
        System.out.println("hello");
    }
}

/**
 * 8锁现象
 * <p>
 * 1.标准访问 先打印邮件还是短信 => 不一定啊 线程star后 由CPU来调用 =>先打印邮件 
 * 2.邮件方法暂停4秒 先打印邮件还是短信 => 邮件 => 同一个对象先执行的获取锁后来的的等待 synchronized 锁住的是当前资源类的对象
 * 3.新增一个普通hello()方法 先打印邮件还是 hello() => 先打印hello => 普通方法不会竞争锁 直接执行
 * 4.两个Phone对象 phone1 phone2 先打印邮件还是短信 =>先打印SMS => 两个不同的对象不是竞争的不是同一把锁 先进方法的先执行
 * 5.两个静态同步方法,,先打印邮件还是短信 => 先打印邮件 => 静态同步方法 都属于类对象 所以是同一把锁 会造成竞争等待
 * 6.一个静态同步方法  一个普通同步方法 => 先打印短信 => 静态的的锁资源属于类,普通方法的锁属于类的对象,不同的锁资源不需要竞争。
 */
public class Lock8 {

    public static void main(String[] args) throws Exception {
        Phone phone = new Phone();
        Phone phone2 = new Phone();


        new Thread(Phone::sendEmail, "A").start();
        Thread.sleep(200); //保证A先启动
        new Thread(phone::sendSMS, "B").start();

    }


}

11.线程不安全集合类

异常:java.util.ConcurrentModificationException

1.List

1.导致原因

​ ArrayList 中的 add方法没有加上锁,多并发情况下上一个线程读数据时候下一个线程进行add操作会导致内存偏移抛出异常

2.解决方案:
1.Vector ()
2.Collections.syschronizedList(new ArrayList<>())
3.CopyOnWriteArrayList()

CopyOnWriteArrayList().add()方法源码

CopyOnWrite容器即是读写分离的容器。往一个容器中添加元素的时候,不直接在当前的Object[]中添加,而是将当前的Object[]Copy一份Object [] newElement, 然后往新容器中添加元素,添加完成之后通过 setArray(newElement)方法讲当前容器指向新的容器,这样做的好处是在并发的情况下发生读的操作时候不需要加上锁,因为当前容器不会添加任何元素。

 public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }

12.JUC辅助类

1.CountDownLatch

配合 countDownLatch.countDown() 与 countDownLatch.await() 控制 执行顺序

package com.lh.juc.jucHelpClassDemo;

import java.util.concurrent.CountDownLatch;

public class CountDownLatchDemo {


    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(6);


        for (int i = 1; i <= 6; i++) {

            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "离开工位");
                countDownLatch.countDown();
            }, String.valueOf(i)).start();
        }
        
        //阻塞 等待 countDown 减完为止
        countDownLatch.await();
        System.out.println(Thread.currentThread().getName()+"所有人都离开完毕 保安关门");
    }
}

2.CyclicBarrier

package com.lh.juc.jucHelpClassDemo;


import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * 计数器 ++
 */
public class CyclicBarrierDemo {

    public static void main(String[] args) {

        CyclicBarrier cyclicBarrier = new CyclicBarrier(6, new Thread(() -> {
            System.out.println("所有员工已经离开");
        }));


        for (int i = 1; i <= 6; i++) {
            int i1 = i;

            new Thread(() -> {
                try {
                    System.out.println("第" + i1 + "员工离开工位");
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }, String.valueOf(i)).start();
        }

    }

}

3.Semaphore

控制并发量

package com.lh.juc.jucHelpClassDemo;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * 控制多线程的并发数
 */
public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3); //控制并发数为3 一共有三个位置

        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                try {
                    semaphore.acquire(1); //线程进入后 剩余最大并发数-1 位置-1
                    System.out.println(Thread.currentThread().getName() + "  进入车位");
                    TimeUnit.SECONDS.sleep(3); //当前抢占到位置的等3秒
                    System.out.println(Thread.currentThread().getName() + "  离开车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    semaphore.release(); //释放当前位置
                }


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

        }
    }


}

4 .ReadWriteLock

多个线程不能同时进行写(读写、写写)的操作

  • 写入没写完成的时候 这时候有个线程来读数据 (不满足数据一直性 即 读写不一致)以下代码会出现这个问题
package com.lh.juc.jucHelpClassDemo;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

class MyCache {
    private volatile Map<String, Object> map = new HashMap<>();

    public void put(String key, String value) {

        try {
            
            System.out.println(Thread.currentThread().getName() + "开始写入");
            TimeUnit.MILLISECONDS.sleep(300);
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "写入成功");
        }catch (Exception e){}finally {
            
        }


    }

    public void get(String key) {

        try {
            
            System.out.println(Thread.currentThread().getName() + "开始读取数据");
            TimeUnit.MILLISECONDS.sleep(300);
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName() + "读取数据成功:" + o);
        }catch (Exception e){}finally {
            
        }
    }

}

public class ReadWriteLockDemo {

    /**
     * 模拟五个线程读 和五个五个线程写
     *
     * @param args
     */

    public static void main(String[] args) {
        MyCache myCache = new MyCache();


        for (int i = 0; i < 6; i++) {
            int i1 = i;
            new Thread(() -> {
                myCache.put(Thread.currentThread().getName(), String.valueOf(i1));
            }, String.valueOf(i)).start();
        }

        for (int i = 0; i < 6; i++) {
            int i1 = i;
            new Thread(() -> {
                myCache.get(Thread.currentThread().getName());

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


    }
}

  • 使用ReadWriteLock后
package com.lh.juc.jucHelpClassDemo;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

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

    public void put(String key, String value) {

        try {
            readWriteLock.writeLock().lock();
            System.out.println(Thread.currentThread().getName() + "开始写入");
            TimeUnit.MILLISECONDS.sleep(300);
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "写入成功");
        }catch (Exception e){}finally {
            readWriteLock.writeLock().unlock();
        }


    }

    public void get(String key) {

        try {
            readWriteLock.readLock().lock();
            System.out.println(Thread.currentThread().getName() + "开始读取数据");
            TimeUnit.MILLISECONDS.sleep(300);
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName() + "读取数据成功:" + o);
        }catch (Exception e){}finally {
            readWriteLock.readLock().unlock();
        }
    }

}

public class ReadWriteLockDemo {

    /**
     * 模拟五个线程读 和五个五个线程写
     *
     * @param args
     */

    public static void main(String[] args) {
        MyCache myCache = new MyCache();


        for (int i = 0; i < 6; i++) {
            int i1 = i;
            new Thread(() -> {
                myCache.put(Thread.currentThread().getName(), String.valueOf(i1));
            }, String.valueOf(i)).start();
        }

        for (int i = 0; i < 6; i++) {
            int i1 = i;
            new Thread(() -> {
                myCache.get(Thread.currentThread().getName());

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


    }
}

13.队列

1.阻塞队列

  • 当队列是空的时候 从队列中获取数据被阻塞 NoSuchElementException
  • 当队列是满的时候 往队列中添加数据被阻塞 Queue full
  • 好处:不需要关系什么时候需要阻塞进程,使用阻塞队列就可以完成了
1.BlockingQueue(接口)
1.ArrayBlockingQueue 数组结构组成的有界阻塞队列
        BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);	
  • add() 队列满了直接抛异常Queue full
  • remove() 队列为空抛异常NoSuchElementException
  • offer() 存入成功返回true,失败返回false
  • offer (e,time,timeType)存入成功返回true,满了等待对应时间后还是不行返回失败false
  • poll() 取出最新的元素 成功返回元素 ,没有返回null
  • **poll(**time,timeType) 取出最新的元素 成功返回元素 ,没有返回等待时间之后还是不行返回null
  • **put()**没有返回值,队列满了进入阻塞 等待
  • **take()**没有返回值,队列空了进入阻塞 等待
2.LinkBlockingQueue 链表组成的有界阻塞队列
3.SynchronousQueue 单个元素的队列

14.线程池

1. 线程池的三大方法

(工作中一般不用 底层队列最大长度是Interger.maxValue很容易 挤压很多个线程 造成OOM)

1.FixedThreadPool 固定线程数线程池
2.newSingleThreadExecutor 一个线程数线程线程池
3.newCachedThreadPool 可伸缩线程数量线程池
package com.lh.juc;

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

public class MyThreadPoolDemo {
    public static void main(String[] args) {

        ExecutorService fixThreadPool = Executors.newFixedThreadPool(5);
        //ExecutorService fixThreadPool = Executors.newSingleThreadExecutor();
       // ExecutorService fixThreadPool = Executors.newCachedThreadPool();

        try {
            for (int i = 0; i < 10; i++) {
                //五个线程执行10个任务
                fixThreadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + " 办理业务");
                });
            }
        } catch (Exception e) {

        } finally {
            fixThreadPool.shutdown();

        }

    }
}

2.源码

//newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
}
    
    
//newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }


//newCachedThreadPool
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
1.七个主要参数
 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;
    }
1.corePoolSize 线程池的核心线程数
2.maximumPoolSize 线程池中最大的线程数 (CPU 最大线程数+1)
System.out.println(Runtime.getRuntime().availableProcessors()); //查看电脑最大核数
3.keepAliveTime 多余空闲线程的存活时间,当线程池中的线程数超过corePoolSize时 超过了 keepAliveTime 多余的线程会被销毁
4.unit keepAliveTime的时间单位
5.wokeQueue 任务队列,被提交但是未被执行的任务
6.threadFactory 表示生成线程池中线程的线程工厂,一般用默认即可
7.handler:拒绝策略,表示当队列满了,并且工作的线程大于等于线程池的最大线程数时,如何来拒绝请求执行的runable策略
2.自定义线程池(重点!!)
package com.lh.juc;

import java.util.concurrent.*;

public class MyThreadPoolDemo {
    public static void main(String[] args) {

        ExecutorService threadPool = new ThreadPoolExecutor(
                2,
                Runtime.getRuntime().availableProcessors()+1, //系统最大核数+1
                2L,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
        );
         //线程池最大容纳数量是 max+队列数
      
        try {
            for (int i = 0; i < 6; i++) {
                threadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + " 办理业务");
                });

            }

        } catch (Exception e) {

        } finally {

        }

    }
}

3.拒绝策略

1.AbortPolicy(默认) 直接抛出RejectedExcecutionException异常
2.CalleRunPolicy: 不会放弃任务也不会抛出异常,将某些任务回退给调用者
3.DiscardOldestPolicy 抛弃队列中等待最久的任务,然后把当前任务加入到队列中尝试再次提交当前任务
4.DisCardPolicy 丢弃无法处理的任务 且不会抛出异常

4.底层原理

步骤:
1.当创建线程池之后,开始等待请求。
2.当调用exectue()方法添加一个请求的任务时,线程池会做做出以下判断
  • 如果正在运行的线程数量小于corePoolSize,马上就会创建线程来执行任务
  • 如果正在运行的线程数量大于corePoolSize ,那么就会把线程方法队列中
  • 如果队列已经满了且正在运行的线程数量还小于maxPoolSize,那么继续创建非核心线程来立即运行这个任务
  • 如果队列满了且正在运行的线程数大于等于maxPoolSize那么线程池会启动拒绝策略来执行
3.当一个线程完成任务时,他就会从队列中取下一个任务来执行
4.当线程池中的某个线程超过keepAliveTime 时
  • 如果当前线程池中的线程数量大于coolPoolSize ,那么这个线程就会被销毁
  • 所以线程池中线程执行完所有的任务后,线程池的小最终会缩到coolPoolSize 的大小

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值