其他分享
首页 > 其他分享> > JUC学习

JUC学习

作者:互联网

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