java并发笔记

wait和sleep的区别

  • wait是Object的方法,sleep是Thread的方法
  • wait会释放锁,sleep不会
  • wait必须在同步代码块中使用,sleep没有要求

Callable和Runnable区别

  • Callable可以有返回值可以抛出异常,Runnable则不行
  • 一个run方法一个call方法

FutureTask实现了Runnable接口,并且FutureTask的构造函数有public FutureTask(Callable<V> callable)public FutureTask(Runnable runnable, V result),所以只要我们拥有一个实现了Callable接口的类,并将其传入FutureTask即可,我们便拥有了实现了Runnable接口的FutureTask类,再通过new Thread(futureTask).start()即可开启新的线程。

Lock锁

  • ReentrantLock
  • ReentrantReadWriteLock.ReadLock
  • ReentrantReadWriteLock.WriteLock

synchronized和lock的区别

  • synchronized是内置的Java关键字;lock是一个Java类
  • synchronized无法判断获取锁的状态;lock可以判断是否获得到了锁
  • synchronized会自动释放锁;lock必须要手动释放锁,否则会出现死锁
  • synchronized是可重入锁,不可以中断,非公平;lock,可重入锁,可以判断锁,非公平

并发下ArrayList不安全的解决方案

  • List<String> list = new Vector<>();

  • List<String> list = Collections.synchronizedList(new ArrayList<>());

  • List<String> list = new CopyOnWriteArrayList<>();(写入时复制,修改后再覆盖)

并发下HashSet不安全的解决方案

  • Set<String> set = Collections.synchronizedSet(new HashSet<>());
  • Set<String> set = new CopyOnWriteArraySet<>();

并发下HashMap不安全

  • ConcurrentHashMap

工具类

  • CountDownLatch
    • countDownLatch.countDown()
    • countDownLatch.await()
  • CyclicBarrier
    • CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> System.out.println("神龙出没"));
    • cyclicBarrier.await()
  • Semaphore
    • semaphore.acquire()获得信号,如果信号量已经满了,等待,等待被释放
    • semaphore.release()释放信号,信号量-1,然后唤醒等待的线程

ReadWriteLock(接口)

  • 实现类ReentrantReadWriteLock

BlockingQueue(接口)

Collection
Queue
BlockingQueue
Deque
List
Set
  • ArrayBlockingQueue

    方式抛出异常有返回值,不抛出异常阻塞 等待超时等待
    添加addofferputoffer
    移除removepolltakepoll
    检测队首元素elementpeek
  • SynchronousQueue(同步队列)

    • put进一个元素后,只能take后,才能继续put元素

线程池(三大方法、7大参数、4种拒绝策略)

  • 优点

    1. 减少资源消耗
    2. 提高系统性能
    3. 方便管理
  • 线程池创建方式

    线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。Executors返回的线程池对象弊端:

    • newFixedThreadPool和newSingleThreadExecutor

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

    • newCachedThreadPool和newScheduledThreadPool

      允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM

  • 三大方法

    • Executors.newSingleThreadExecutor() 单个线程
    • newFixedThreadPool(5) 固定线程池大小
    • newCachedThreadPool() 可伸缩线程池大小
  • 7大参数

    • corePoolSize 核心线程池大小

    • maximumPoolSize 最大核心线程池大小

      线程池的最大大小如何设置

      • CPU 密集型,几核,就是几,可以保持CPU的效率最高

      • IO 密集型 判断你的程序中十分耗IO的线程 x 2

    • keepAliveTime 存活时间

    • unit 超时单位

    • workQueue 阻塞队列

    • threadFactory 线程工厂,创建线程的,一般默认不用管

    • handler 拒绝策略

    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;
        }
    
  • 4种拒绝策略

    • new ThreadPoolExecutor.AbortPolicy() 所有的线程都在处理任务,并且阻塞队列也满了,就会抛出异常
    • new ThreadPoolExecutor.CallerRunsPolicy() 被拒绝的任务在调用线程的方法中运行,不抛出异常
    • new ThreadPoolExecutor.DiscardPolicy() 被拒绝的任务会被抛弃,不抛出异常
    • new ThreadPoolExecutor.DiscardOldestPolicy() 抛弃最早的未被处理的进入线程池的任务,并尝试重新执行当前的新任务,不抛出异常

函数式接口

  • Function函数式接口 有一个输入参数,有一个输出
  • Predicate断定型接口 有一个输入参数,返回值只能是 布尔值
  • Consumer消费型接口 只输入不返回
  • Supplier供给型接口 只返回不输入

ForkJoin

  • 特点:工作窃取

    有的线程把自己队列中的任务干完之后,会去其他线程的队列中窃取一个任务执行,通常使用双端队列,被窃取任务的线程从双端队列头部拿任务执行,窃取任务的线程从双端队列尾部拿任务执行

    • 优点:充分利用线程进行并行计算,减少线程间的竞争
    • 缺点:消耗更多系统资源,只有一个任务时会出现竞争
  • 主要步骤

    • 分割任务:需要一个fork类把大任务拆成子任务,子任务太大可能还要分割
    • 执行任务并合并结果:子任务在双端队列中执行,结果统一放在一个队列里,启动一个线程从队列里拿数据,然后合并这些数据
  • ForkJoinTask:创建fork-join任务,提供了fork()和join()实现机制,通常情况下继承它的子类即可:

  • RecursiveAction(无返回值),RecursiveTask(有返回值)

  • ForkJoinPool:执行fork-join任务

异步任务

  • 异步执行、成功回调、失败回调

  • CompletableFuture

    使用

    • CompletableFuture.runAsync()
    • CompletableFuture.supplyAsync()

JMM

java内存模型,不存在的东西,一种概念

  • 线程解锁前,必须把共享变量立刻刷新回主存
  • 线程加锁前,必须读取主存中的最新值到工作内存中
  • 加锁和解锁是同一把锁

线程 工作内存、主内存

  • 8种操作

    • lock unlock

    • read load

    • use assign

    • write store

Volatile

Volatile是Java虚拟机提供的轻量级同步机制

作用

  1. 保证可见性(保证线程知道主内存中值得变化)

  2. 不保证原子性

    如果不使用lock和synchronized,怎么保证原子性

    • 使用原子类 AtomicInteger类
  3. 禁止指令重排

    • 增加内存屏障,保证特定的操作的执行顺序
    • 保证某些变量的内存可见性(利用这些特性volatile实现了可见性)

单例模式

  • 饿汉式
  • 懒汉式、DCL懒汉式
  • 静态内部类写法

单例不安全 -> 反射 -> 枚举类

CAS

  • 比较并交换

    比较当前工作内存中的值和主内存中的值,如果这个值是期望的,就执行操作,否则就一直循环

  • 缺点

    1. 循环会耗时(自旋锁)
    2. 一次只能保证一个共享变量的原子性
    3. ABA问题 -> 原子引用(AtomicStampedReference)(乐观锁)

各种锁

公平锁、非公平锁

  • 公平锁:非常公平,不能插队,必须先来后到
  • 非公平锁:非常不公平,可以插队(默认都是非公平锁)

可重入锁(递归锁)

拿到了外面的锁就可以拿到里面的锁

自旋锁

myLock()方法利用的CAS,当第一个线程A获取锁的时候,能够成功获取到,不会进入while循环,如果此时线程A没有释放锁,另一个线程B又来获取锁,此时由于不满足CAS,所以就会进入while循环,不断判断是否满足CAS,直到A线程调用myUnLock方法释放了该锁,线程B才会退出循环。

死锁

两个线程互相持有对方需要的资源

package com.shayne.deadlock;

/**
 * 死锁例子
 */
public class DeadLockDemo {

    public static void main(String[] args) {

        MyThread myThread = new MyThread();

        new Thread(myThread).start();
        new Thread(myThread).start();
    }
}

class MyThread implements Runnable{

    Object A = new Object();
    Object B = new Object();

    boolean flag = true;

    @Override
    public void run() {
        if (flag) {
            flag = false;
            a();
        } else {
            b();
        }
    }

    public void a() {
        synchronized (A) {
            System.out.println(Thread.currentThread().getName() + " get A lock...");     
            b();
        }
    }

    public void b() {
        synchronized (B) {
            System.out.println(Thread.currentThread().getName() + " get B lock...");
            a();
        }
    }
}

chronized (A) {
System.out.println(Thread.currentThread().getName() + " get A lock…");
b();
}
}

public void b() {
    synchronized (B) {
        System.out.println(Thread.currentThread().getName() + " get B lock...");
        a();
    }
}

}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值