JUC学习-5-ReadWriteLock-ArrayBlockingQueue-SynchronousQueue-线程池

ReadWriteLock

/*
 * 独占锁(写锁)一次只能被一个线程占有
 * 共享锁(读锁) 多个线程可以同时占有
 * ReadWriteLock
 * 读-读 可以共存
 * 读-写 不能共存
 * 写-写 不能共存
 *
 * */

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

        for (int i = 1; i <= 10; i++) {
            int finalI = i;
            new Thread(() -> {
                myCacheLock.put(finalI + "", finalI);
            }, String.valueOf(i)).start();
        }

        for (int i = 1; i <= 10; i++) {
            int finalI = i;
            new Thread(() -> {
                myCacheLock.get(finalI + "");
            }, String.valueOf(i)).start();
        }

    }
}


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

    public void put(String key, Object value) {
        System.out.println(Thread.currentThread().getName() + "写入" + key);
        map.put(key, value);
        System.out.println(Thread.currentThread().getName() + "写入OK");
    }

    public void get(String key) {
        System.out.println(Thread.currentThread().getName() + "读取" + key);
        Object o = map.get(key);
        System.out.println(Thread.currentThread().getName() + "读取OK");
    }
}

class MyCacheLock {
    private volatile Map<String, Object> map = new HashMap<>();
    // 读写锁 更加细粒度的操作
    // 写的时候只能有一个线程写 读的时候所有人都可以读
    private ReadWriteLock lock = new ReentrantReadWriteLock();

    public void put(String key, Object value) {

        try {
            lock.writeLock().lock();
            System.out.println(Thread.currentThread().getName() + "写入" + key);
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "写入OK");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.writeLock().unlock();
        }
    }

    public void get(String key) {
        try {
            lock.readLock().lock();
            System.out.println(Thread.currentThread().getName() + "读取" + key);
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName() + "读取OK");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.readLock().unlock();
        }

    }
}

阻塞队列

写入:如果队列满了,就必须阻塞等待

取:如果队列是空的,必须阻塞等待生产

什么情况下我们回使用阻塞队列 多线程并发处理 线程池

学习使用队列

四组API

方式 抛出异常 不会抛出异常/有返回值 阻塞等待 超时等待
添加 add offer put offer(e, timeout, unit)
移除 remove poll take poll(timeout, unit)
检测队首元素 element peek - -
  /*
     * 抛出异常
     * */
    public static void tesst1() {
        ArrayBlockingQueue<Object> bockingQueue = new ArrayBlockingQueue<>(3);
        System.out.println(bockingQueue.add("a"));
        System.out.println(bockingQueue.add("b"));
        System.out.println(bockingQueue.add("c"));


        // java.lang.IllegalStateException Queue full 队列已满
        // System.out.println(bockingQueue.add("d"));

        System.out.println(bockingQueue.remove());
        System.out.println(bockingQueue.remove());
        System.out.println(bockingQueue.remove());
        // 查看队首元素 java.util.NoSuchElementException 无元素
        //  System.out.println(bockingQueue.element());

        // java.util.NoSuchElementException 无元素
        // System.out.println(bockingQueue.remove());
    }
/*
 * 不会抛出异常/有返回值
 * */
public static void tesst2() {
    ArrayBlockingQueue<Object> bockingQueue = new ArrayBlockingQueue<>(3);
    System.out.println(bockingQueue.offer("a"));
    System.out.println(bockingQueue.offer("b"));
    System.out.println(bockingQueue.offer("c"));

    // 返回false
    System.out.println(bockingQueue.offer("d"));

    System.out.println(bockingQueue.poll());
    System.out.println(bockingQueue.poll());
    System.out.println(bockingQueue.poll());
    // 返回null
      System.out.println(bockingQueue.peek());
    // 返回null
    System.out.println(bockingQueue.poll());
}
  /*
     * 阻塞等待 (一直阻塞)
     * */
    public static void test3() throws InterruptedException {
        ArrayBlockingQueue<Object> bockingQueue = new ArrayBlockingQueue<>(3);
        bockingQueue.put("a");
        bockingQueue.put("b");
        bockingQueue.put("c");

        // 一直阻塞
//        bockingQueue.put("d");

        System.out.println(bockingQueue.take());
        System.out.println(bockingQueue.take());
        System.out.println(bockingQueue.take());
        // 一直阻塞
        System.out.println(bockingQueue.take());
    }
/*
 * 阻塞等待 (超时退出)
 * */
public static void test4() throws InterruptedException {
    ArrayBlockingQueue<Object> bockingQueue = new ArrayBlockingQueue<>(3);
    bockingQueue.offer("a");
    bockingQueue.offer("b");
    bockingQueue.offer("c");

    // 2秒超时退出
    bockingQueue.offer("d", 2, TimeUnit.SECONDS);
    System.out.println(bockingQueue.poll());
    System.out.println(bockingQueue.poll());
    System.out.println(bockingQueue.poll());
    // 2秒超时退出 返回null
    System.out.println(bockingQueue.poll(2, TimeUnit.SECONDS));
}

同步队列 SynchronousQueue

没有容量 进去一个 元素,必须等待取出来之后 才能继续添加元素

put take

/*
 * 同步队列
 * 和其他的BlockingQueue不一样 SynchronousQueue 不存储元素
 * put了一个元素 必须从里面take取出来 否则不能再put进去元素
 *
 * */
public class SynchronousQueueDemo {
    public static void main(String[] args) {
        SynchronousQueue synchronousQueue = new SynchronousQueue();

        new Thread(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + "put1");
                synchronousQueue.put("1");
                System.out.println(Thread.currentThread().getName() + "put2");
                synchronousQueue.put("2");
                System.out.println(Thread.currentThread().getName() + "put3");
                synchronousQueue.put("3");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "T1").start();

        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
                System.out.println(synchronousQueue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(synchronousQueue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(synchronousQueue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "T2").start();
    }
}

线程池

三大方法 七大参数 四种拒绝策略

池化技术

程序的运行就会占用系统的资源 优化资源的使用 => 池化技术

线程池 连接池 内纯池 对象池... 创建 销毁非常浪费资源

池化技术: 事先准备好一些资源 有人要用 就来池子里面来拿 用完之后还回来

线程池的好处:

  1. 降低资源的消耗
  2. 提高响应的速度
  3. 方便管理

可以复用 可以控制最大并发数

三大方法

// Executors 工具类 三大方法
// 使用线程池之后 要使用线程池创建线程

public class Demo01 {
    public static void main(String[] args) {
//        ExecutorService threadPool = Executors.newSingleThreadExecutor();// 单个线程
        ExecutorService threadPool = Executors.newFixedThreadPool(5);// 创建固定大小的线程池
//        ExecutorService threadPool = Executors.newCachedThreadPool();// 可伸缩的


        try {
            for (int i = 0; i < 10; i++) {
                threadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "=====");
                });
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 线程池使用完毕后 程序结束 关闭线程池
            threadPool.shutdown();
        }

    }
}

七大参数 源码分析

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

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

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
// 本质 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.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

最大承载 = 最大核心线程池大小 + 阻塞队列

四种拒绝策略

AbortPolicy 默认的拒绝策略 队列满了,不处理新来的 抛出异常

CallerRunsPolicy 那来的去哪里

DiscardPolicy 队列满了 丢掉任务 不会抛出异常

DiscardOldestPolicy 队列满了 尝试和最早的竞争 丢掉任务 不会抛出异常

最大线程该如何定义


CPU密集型

多条线程同时执行 几核就是几 可以保证CPU的效率最高

Runtime.getRuntime().availableProcessors() 获得当前电脑的逻辑核心

IO密集型

IO 十分占用资源 判断你的程序有多少个处理IO的的线程,然后留一些给做其他任务做

posted @ 2021-07-15 19:27  野兽Gentleman  阅读(41)  评论(0编辑  收藏  举报