ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

JUC学习

2022-07-23 14:35:17  阅读:80  来源: 互联网

标签:JUC Thread System 学习 线程 println new out


JUC学习

1、线程的状态

 public enum State {
     
     // 新建
     NEW,
 ​
     // 运行
     RUNNABLE,
 ​
     // 阻塞
     BLOCKED,
 ​
     // 等待(一直等)
     WAITING,
 ​
     // 等待(超时等待)
     TIMED_WAITING,
 ​
     // 终止
     TERMINATED;
 }

 

辅助类

CountDownLatch(减法计数器)

 public static void main(String[] args) throws InterruptedException {
 ​
     CountDownLatch countDownLatch = new CountDownLatch(10);
 ​
     for (int i = 0; i < 10; i++) {
         new Thread(() -> {
             System.out.println(Thread.currentThread().getName());
             // 数量减一
             countDownLatch.countDown();
        },String.valueOf(i)).start();
    }
 ​
     // 等待10个线程执行结束再往下执行(计数器为0时)
     countDownLatch.await();
 ​
     System.out.println("所有线程执行完毕!");
 }

 

CyclicBarrier(加法计数器)

 public static void main(String[] args) throws InterruptedException {
     /**
      * 集齐7颗龙珠,召唤神龙
      */
     CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> System.out.println("召唤神龙!"));
 ​
     for (int i = 1; i <= 7; i++) {
         final int j = i;
         new Thread(() -> {
             System.out.println(Thread.currentThread().getName() + "集齐第" + j + "颗龙珠");
             try {
                 // 等待
                 cyclicBarrier.await();
            } catch (InterruptedException e) {
                 e.printStackTrace();
            } catch (BrokenBarrierException e) {
                 e.printStackTrace();
            }
        }).start();
    }
 }

 

Semaphore(信号量)

 public static void main(String[] args) throws InterruptedException {
     // 指定线程数:停车位
     Semaphore semaphore = new Semaphore(3);
 ​
     for (int i = 1; i <= 6; i++) {
         new Thread(() -> {
             try {
                 // 得到
                 semaphore.acquire();
                 System.out.println(Thread.currentThread().getName() + "抢到车位");
                 TimeUnit.SECONDS.sleep(1);
                 System.out.println(Thread.currentThread().getName() + "离开车位");
            } catch (InterruptedException e) {
                 e.printStackTrace();
            } finally {
                 // 释放
                 semaphore.release();
            }
        }, String.valueOf(i)).start();
    }
 }

应用场景:限流

 

读写锁:ReentrantReadWriteLock

 public static void main(String[] args) throws InterruptedException {
 ​
     MyCache myCache = new MyCache();
 ​
     // 5个线程写
     for (int i = 1; i <= 5; i++) {
         final int j = i;
         new Thread(() -> myCache.put(String.valueOf(j), j),String.valueOf(i)).start();
    }
 ​
     // 5个线程读
     for (int i = 1; i <= 5; i++) {
         final int j = i;
         new Thread(() -> myCache.get(String.valueOf(j)), String.valueOf(i)).start();
    }
 }
 ​
 class MyCache {
 ​
     private Map<String,Object> map = new HashMap<>();
     // 读写锁
     private ReadWriteLock lock = new ReentrantReadWriteLock();
 ​
     // 写的时候,我们只希望一个线程写
     public void put(String key, Object value) {
         lock.writeLock().lock();
         try {
             System.out.println(Thread.currentThread().getName() + "写入" + key);
             map.put(key, value);
             System.out.println(Thread.currentThread().getName() + "写入OK");
        } finally {
             lock.writeLock().unlock();
        }
    }
 ​
     // 读的时候我们希望多个线程读
     public void get(String key) {
         lock.readLock().lock();
         try {
             System.out.println(Thread.currentThread().getName() + "读取" + key);
             Object value = map.get(key);
             System.out.println(Thread.currentThread().getName() + "读取OK");
        } finally {
             lock.readLock().unlock();
        }
    }
 }

 

 

阻塞队列(BlockingQueue)

四组API

方式抛出异常有返回值,不抛出异常阻塞等待超时等待
添加 add() offer() put() offer()
移除 remove() poll() take() poll()
检测队首元素 element() peek() - -

 

线程池

三大方法

 public static void main(String[] args) {
         // 单个线程
         ExecutorService threadPool = Executors.newSingleThreadExecutor();
         // 固定数量线程
 //       ExecutorService threadPool = Executors.newFixedThreadPool(5);
         // 颗伸缩的,遇强则强,与弱则弱
 //       ExecutorService threadPool = Executors.newCachedThreadPool();
 ​
         for (int i = 0; i < 10; i++) {
             threadPool.execute(() -> {
                 System.out.println(Thread.currentThread().getName() + ":hello world");
            });
        }
 ​
         threadPool.shutdown();
    }

 

七大参数

 // 通过Executors创建线程池的本质
 public ThreadPoolExecutor(int corePoolSize, // 核心线程数大小
                           int maximumPoolSize, // 最大线程数大小
                           long keepAliveTime, // 存活时间,超过这个时间未调用就释放
                           TimeUnit unit, // 时间单位
                           BlockingQueue<Runnable> workQueue,  // 阻塞队列
                           ThreadFactory threadFactory,  // 线程工厂,一般不用动                  
                           RejectedExecutionHandler handler) // 拒绝策略

 

四种拒绝策略

 new ThreadPoolExecutor.AbortPolicy();       // 线程数超出  (最大线程数 + 阻塞队列长度) 则抛出异常
 new ThreadPoolExecutor.CallerRunsPolicy();  // 哪来的去哪里 不会抛出异常
 new ThreadPoolExecutor.DiscardPolicy(); // 队列满了,丢掉任务 不会抛出异常
 new ThreadPoolExecutor.DiscardOldestPolicy(); // 队列满了,尝试和第一个竞争,失败再丢掉任务 不会抛出异常

 

总结

不推荐使用Executors创建线程,而是使用ThreadPoolExecutor创建线程。

Executors是不安全的,有可能会把资源耗尽的风险

Executors弊端如下:

  1. Executors.newFixedThreadPool() 和 Executors.newSingleThreadExecutor()

    • 允许请求队列长度为Integer.MAX_VALUE(约21亿),可能会堆积大量的请求,从而导致OOM

  2. Executors.newCachedThreadPool() 和 Executors.newScheduledThreadPool()

    • 允许创建线程数量为Integer.MAX_VALUE(约21亿),可能会创建大量线程,从而导致OOM

 

最大线程数到底该如何定义

  1. CPU密集型,几核就定义几,可以保持CPU的效率最高

    // 通过java代码获取CPU核心数
    System.out.println(Runtime.getRuntime().availableProcessors());
  2. IO 密集型

    一般设置要大于程序中比较耗IO资源的线程

 

Volatile关键字

volatile是java虚拟机提供的轻量级的同步机制

  1. 保证可见性

  2. 不保证原子性

  3. 禁止指令重排

 

什么是JMM?

java内存模型,不存在的东西,是一种概念也是一种约定

 

关于JMM的一些同步约定:

  1. 线程解锁前,必须把共享变量==立刻==刷回主存

  2. 线程加锁前,必须读取主存中最新值到工作内存中

  3. 加锁和解锁必须是同一把锁

 

保证可见性

// 不加volatile,程序就会进入死循环
private volatile static int a;

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

new Thread(() -> {
while (a == 0) { // 会进入死循环,此线程对主内存的变化是不知道的

}
}).start();

TimeUnit.SECONDS.sleep(1);

a = 1;

System.out.println("a = " + a);

}

 

不保证原子性

 private volatile static int a;
 ​
 public static void add() {
     a ++;
 }
 ​
 public static void main(String[] args) throws InterruptedException {
 ​
     for (int i = 0; i < 20; i++) {
         new Thread(() -> {
             for (int j = 0; j < 1000; j++) {
                 add();
            }
        }).start();
    }
 ​
     while (Thread.activeCount() > 2) {
         Thread.yield();
    }
 ​
     System.out.println("a = " + a);
 }

 

 

自定义自旋锁

 public class SpinLock {
 ​
     private static AtomicReference<Integer> atomicReference = new AtomicReference<>(1);
 ​
     public void lock() {
         while (!atomicReference.compareAndSet(1, 2)) {
 ​
        }
 ​
         System.out.println(Thread.currentThread().getName() + "加锁成功");
    }
 ​
     public void unlock() {
         atomicReference.compareAndSet(2, 1);
         System.out.println(Thread.currentThread().getName() + "解锁");
    }
 }
 

标签:JUC,Thread,System,学习,线程,println,new,out
来源: https://www.cnblogs.com/zhouqiangshuo/p/16511950.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有