juc并发编程复习(上篇)(10.30)

juc并发编程

java.util.concurrent

java.util.atomic

java.util.concurrent.locks

Runable 没有返回值,效率相比Callable较低

线程与进程

一个进程往往包含多个线程

java默认两个线程:main GC

java不可以开启线程,调用的本地方法(native),调用底层c++

并发与并行

并发:多线程操作同一资源

  • cpu一核,模拟多个线程,快速交替执行

并行:多个线程同时执行

  • cpu多核,多个线程同时执行:线程池

线程6个状态

  • 新生

  • 运行

  • 阻塞

  • 等待,死死地等

  • 超时等待

  • 终止

wait/sleep区别

来自不同的类

  • wait:Object

  • sleep:Thread

锁的释放

  • wait:会释放锁

  • sleep:不会释放锁

使用范围

  • wait:同步代码块

  • sleep:任何地方

是否需要捕获异常

  • wait:不需要捕获异常

  • sleep:需要捕获异常

Lock锁

传统Synchronized

本质:队列,锁

Lock接口

实现类:

  • 可重入锁(ReentrantLock)(常用)

    • 默认非公平锁,可以通过增加构造参数实现公平锁

  • 读锁(ReentrantReadWriteLock.ReadLock)

  • 写锁(ReentrantReadWriteLock.WriteLock)

公平锁:先来后到

非公平锁:可以插队(默认)

线程就是一个单独的资源类

并发:多线程操作同一个资源类,把资源类丢进线程

@Functionalinterface

函数式接口,jdk1.8 lambda表达式

(参数)->{代码}

Lock三部曲
  1. new ReentrantLock();

  2. lock.lock();//加锁

  3. finally => lock.unlock;//解锁

Synchronzied和Lock区别
  1. Synchronzied内置的java关键字,Lock一个java类

  2. Synchronzied无法判断获得锁的状态,Lock可以判断是否获得了锁

  3. Synchronzied会自动释放锁,Lock必须手动释放锁,如果不释放就死锁

  4. Synchronzied线程1(获得锁,阻塞),线程2(等待,傻傻的等),Lock锁不一定会一直等待下去

  5. Synchronzied可重入锁,不可以中断,非公平,Lock可重入锁,可以判断锁,非公平(可以设置公平)

  6. Synchronzied适合少量代码的同步问题,Lock适合大量代码的同步问题

生产者消费者问题

Synchronzied

Synchronzied修饰方法,使用wait()函数进行等待,使用notifyAll()函数通知其他进程

等待的代码块要用while进行循环判断,而不是使用if,防止虚假唤醒问题

juc

Lock lock = new ReentrantLock();

Condition condition = lock.newCondition();

Condition conditionA = lock.newCondition();

lock.lock();

condition.await(); // 等待

condition.signalAll(); // 唤醒全部

conditionA.signal();//唤醒指定

finally => lock.unlock();

锁的对象

普通同步方法:锁的是调用者(当前资源类对象 new)

静态同步方法:锁的是Class模板类(static)

集合类不安全

list不安全

java.util.ConcurrentModificationException 并发修改异常

并发下 ArrayList 不安全(Synchronized) 解决方案;

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

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

  • 3、List<String> list = new CopyOnWriteArrayList<>();

CopyOnWrite 写入时复制 COW 计算机程序设计领域的一种优化策略; 多个线程调用的时候,list,读取的时候,固定的,写入(覆盖) 在写入的时候避免覆盖,造成数据问题! 读写分离

Set不安全

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

  • Set<String> set = new CopyOnWriteArraySet<>();

Map 不安全

  • Map<String, String> map = new ConcurrentHashMap<>();

Callable

与runable相比

1、可以有返回值

2、可以抛出异常

3、方法不同,run()/ call()

FutureTask(runable的一个实现类)

new Thread(new FutureTask<V>( Callable )).start();

class MyThread implements Callable<V> {@Override call();}

细节: 1、有缓存(效率高) 2、结果可能需要等待,会阻塞!

辅助类

CountDownLatch减法计数器

countDownLatch.countDown(); // 数量-1

countDownLatch.await(); // 等待计数器归零,然后再向下执行

每次有线程调用 countDown() 数量-1,假设计数器变为0,countDownLatch.await() 就会被唤醒,继续执行!

CyclicBarrier加法计数器

CyclicBarrier cyclicBarrier = new CyclicBarrier(终值,lambda表达式(当到达终值时要执行,类似于回调函数));

cyclicBarrier.await(); // 等待

Semaphore信号量

Semaphore semaphore = new Semaphore(资源数量);

semaphore.acquire();// acquire() 得到

finally => semaphore.release(); // release() 释放

semaphore.acquire() 获得,假设如果已经满了,等待,等待被释放为止!

semaphore.release(); 释放,会将当前的信号量释放 + 1,然后唤醒等待的线程!

作用: 多个共享资源互斥的使用!并发限流,控制最大的线程数!

读写锁

读可以多线程同时读

写只可以一个线程写

  • 独占锁(写锁) 一次只能被一个线程占有

  • 共享锁(读锁) 多个线程可以同时占有

  • ReadWriteLock

  • 读-读 可以共存!

  • 读-写 不能共存!

  • 写-写 不能共存!

// 读写锁: 更加细粒度的控制

private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

private Lock lock = new ReentrantLock();

// 存,写入的时候,只希望同时只有一个线程写

readWriteLock.writeLock().lock();

finally => readWriteLock.writeLock().unlock();

// 取,读,所有人都可以读!

readWriteLock.readLock().lock();

finally => readWriteLock.readLock().unlock();

猜你喜欢

转载自blog.csdn.net/m0_62261710/article/details/143368844