JUC并发编程

JUC并发编程

1. 线程间定制化通信

  1. 指定每个线程的执行顺序
  2. 为每个线程都设置一个标志位,只有当是当前线程的标志位时才让该线程执行,且执行后修改标志位并通知下一个线程执行,只通知指定进程就行
  3. 为了实现定制化通知,故必须为每个线程创建一个Condition,此时通知时只需要使用对应的Condition进行通知即可
  4. 为了防止虚假唤醒,必须要在while()循环判断,且在内部进行进行等待,此时唤醒后仍会进行判断,从而避免了虚假唤醒问题
  5. 使用Lock实现线程间通信
    1. 创建资源类在资源类中定义属性和操作方法
    2. 在操作方法中实现 判断、干活、通知
    3. 创建多个线程,调用操作方法
    4. 在Lock中存在一个Condition对象,通过newCondition()创建一个Condition对象并返回Condition对象就相当于一个锁,可以实现进程间的通信
    5. 通过Condition对象的await()和signal()方法可以实现进程间的通信
    6. 为了防止虚假唤醒问题,必须在while()循环中进行wait(),必须在while中进行wait()防止虚假唤醒,此时唤醒后仍会进行判断,从而防止虚假唤醒
    7. Lock中的Condition对象可以实现进程间的通信,通过await()和signal()来睡眠和唤醒进程
    8. Lock接口中通过Condition.await()方法进行等待,通过Condition.signal()方法进行唤醒
    9. 在哪里睡就在哪里醒,故必须在while里面睡,以防止虚假唤醒问题

2. 线程不安全问题

  1. List集合线程不安全演示
    1. List集合的方法没有Synchronized关键字标识,故多个线程同时操作时可能出现线程不安全问题,如存在并发修改问题
    2. 主线程中创建的子线程可以直接调用主线程中的对象,主线程中创建的子线程可以直接调用主线程的对象
    3. 解决方案-Vector
      1. Vector集合中的方法加了Synchronized关键字,此时就可以避免出现线程不安全问题
      2. Vector集合中的方法都加了Synchronized关键字,故可以解决并发修改的问题,确保每次只有一个对象可以访问Synchronized作用范围的代码
    4. 解决方案-Collections
      1. 也可以通过Collections集合类中的synchronizedList()方法传入一个List对象,此时就会返回一个线程安全的List对象
    5. 解决方案-CopyOnWriteArrayList
      1. 通过JUC提供的CopyOnWriteArrayList类解决集合的线程不安全问题
      2. 写时复制技术读集合时可以并发读写集合时先复制一份集合,然后写入新复制的集合,与旧集合合并,以后从新集合中读取内容
      3. 实现并发读,也实现了独立写操作
      4. 写操作时加锁读操作时不加锁,且写操作是先复制一份再写入然后覆盖原来的集合
  2. HashSet集合线程不安全问题
    1. HashSet集合的方法也没有使用Synchronized关键字实现线程安全,故此时多线程操作时可能出现并发修改问题,多个线程同时修改
    2. 使用JUC的CopyOnWriteArraySet来解决
      1. 还是利用写时复制技术,实现并发读和独立写
      2. 写操作时先复制一份,然后对新的写入,最后覆盖原来的,从而实现独立写
      3. 读操作不加锁,写操作加锁
  3. HashMap线程不安全演示
    1. HashMap中的方法也是线程不安全的没有使用Synchronized关键字,故当多个线程时就会出现线程不安全问题,可能会并发修改问题
    2. 使用 ConcurrentHashMap类解决HashMap的线程不安全问题

3. 多线程锁

  1. Synchronized锁的8种情况
    1. 每一个对象都可以看做一个锁,当执行Synchronized同步代码块时,相当于用该对象进行加锁,此时该对象就会被占用,就无法再执行别的同步代码块,但可以执行非同步代码,因为非同步代码不需要加锁

    2. 每个对象只可以同时执行一个Synchronized关键字作用范围的代码,如果要执行多个,则必须解锁后才可以执行下一个同步方法,但可以同时执行多个非同步方法

    3. 多个对象执行同步方法时,会先抢锁,先得到的先执行,未抢到锁则会等待

    4. 静态方法中的this是类的Class对象,是唯一的,故不可以同时执行一个类中多个静态同步方法,因为一个对象只可以同时执行一个同步方法,被加锁了就无法再执行别的同步方法

    5. Java中的每一个对象都可以作为锁每一个对象同一时刻只可以执行一个同步方法 ![[attachments/Pasted image 20241122135730.png]]

    6. Synchronized标注普通同步方法时,此时锁的对象是调用该方法的this对象

    7. 标注静态方法时,此时锁的对象是类的Class对象

    8. 标注代码块时,此时锁的对象是代码块括号内配置的对象

    9. 执行同步方法的同时可以执行非同步方法

  2. 公平锁和非公平锁
    1. 非公平锁可能造成线程被饿死的情况,但执行的效率高直接执行,不会先看队列是否为空
    2. 公平锁的效率相对低先看队列是否为空为空时执行,不为空时加入队列排队
    3. 公平锁是加入队列进行排队非公平锁是直接执行,不会排队
    4. 公平锁效率低,非公平锁效率高,但会线程饿死
  3. 可重入锁
    1. 当一个线程已经占有一个可重入锁时,在锁中再次申请该锁时会直接获得而不会阻塞
    2. 非可重入锁时,此时线程再次申请锁时就会造成死锁
    3. Synchronized(隐式,自动加锁解锁)Lock(显式,手动加锁解锁) 都是可重入锁;使用Synchronized时不需要手动加锁解锁,但使用Lock时必须手动加锁解锁,且一定要保证加锁和解锁的次数对应
    4. 一个对象同一时间只可以执行一个同步操作,因为此时会被加锁,但可以执行多个非同步操作,因为非同步操作不会加锁
    5. 每一个对象都可以看作一个锁同步方法时会对当前对象加锁,此时该对象就无法再执行别的同步方法了,一个对象同一时刻最多只可执行一个同步方法
  4. 死锁
    1. 定义:两个或者两个以上线程因为争夺资源而造成的相互等待现象如果没有外力干涉,将无法继续执行下去,无外力干涉时,将无法继续执行
    2. 产生死锁的原因
      1. 系统资源不足
      2. 进程运行推进顺序不合适
      3. 资源分配不当
    3. 死锁案例:两个线程分别占有一个锁,此时分别去获取另一个线程的锁时就会出现死锁现象,此时会因为竞争资源而造成相互等待现象
    4. 验证是否发生了死锁
      1. jps类型于linux ps -ef查看运行中的进程
      2. jstackJVM自带的堆栈跟踪工具指定进程号来判断某个进程是否发生了死锁
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值