【JUC】并发编程学习笔记(二)
创始人
2024-03-14 08:21:13

JUC并发编程

  • 五、多线程锁
    • 5.1、synchronized实现同步的基础
    • 5.2、公平锁与非公平锁
    • 5.3、可重入锁
    • 5.4、死锁
      • 5.4.1、概念
      • 5.4.2、案例
      • 5.4.3、查看死锁
  • 六、Callable接口
    • 6.1、概述
    • 6.2、FutureTask概述和原理
    • 6.3、案例
  • 七、辅助类
    • 7.1、减少计数CountDownLatch
    • 7.2、循环棚栏CyclicBarrier
    • 7.3、信号灯Semaphore

五、多线程锁

5.1、synchronized实现同步的基础

Java中的每一个对象都可以作为锁。
具体表现为以下3种形式。

  • 对于普通同步方法,锁是当前实例对象。
  • 对于静态同步方法,锁是当前类的class对象。
  • 对于同步方法块,锁是synchonized括号里配置的对象

5.2、公平锁与非公平锁

//创建非公平锁
//可能一个线程吃掉所有任务 其他线程被“饿死” 但效率高
private final ReentrantLock lock = new ReentrantLock(false);
//创建公平锁
//每个线程都领到任务 但效率降低
private final ReentrantLock lock = new ReentrantLock(true);

5.3、可重入锁

同一个线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁(前提是锁对象得是同一个对象),不会因为之前已经获取过锁还没有释放而发生阻塞

class RLock {public synchronized void add(){add();}
}
public class Demo06 {public static void main(String[] args) {new RLock().add();}
}

此时不会堵塞 只会栈溢出java.lang.StackOverflowError

5.4、死锁

5.4.1、概念

两个或者两个以上进程在执行过程中,因为争夺资源而造成一种互相等待的现象。如果没有外力干涉,他们无法再执行下去。
在这里插入图片描述

产生死锁原因:

  1. 系统资源不足
  2. 进程运行推进顺序不合适
  3. 资源分配不当

5.4.2、案例

import java.util.concurrent.TimeUnit;public class DeadLock {static Object o1=new Object();static Object o2=new Object();public static void main(String[] args) {new Thread(()->{synchronized (o1){System.out.println(Thread.currentThread().getName()+"持有o1,试图获取o2");try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}synchronized (o2){System.out.println(Thread.currentThread().getName()+"获取o2");}}},"aa").start();new Thread(()->{synchronized (o2){System.out.println(Thread.currentThread().getName()+"持有o2,试图获取o1");try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}synchronized (o1){System.out.println(Thread.currentThread().getName()+"获取o1");}}},"bb").start();}
}

5.4.3、查看死锁

  1. jps
    先输入jps -l找到进程号
  2. jstack
    jvm自带堆栈跟踪工具
    输入jstack 进程号在最后提示Found xxx deadlock.发现xx个死锁

在这里插入图片描述
在这里插入图片描述

六、Callable接口

6.1、概述

通过使用Runnable 创建线程。但是,Runnable 缺少的一项功能是,当线程终止时(即run ( )完成时),我们无法使线程返回结果。为了支持此功能,Java中提供了Callable接口。

RunnableCallable
是否有返回值
是否抛出异常
实现方法run()call()

6.2、FutureTask概述和原理

FutureTask类 实现了RunnableFuture接口,而RunnableFuture 继承了Runnable和Future接口,所以本质上 FutureTask是Runnable的一种实现。

6.3、案例

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;//比较Callable Runable
class MyThread1 implements Runnable{@Overridepublic void run() {}
}
class MyThread2 implements Callable{@Overridepublic Integer call() throws Exception {return 200;}
}
public class Demo1 {public static void main(String[] args) throws ExecutionException, InterruptedException {//创建Runable线程new Thread(new MyThread1(),"aa").start();//创建Callable线程//不能直接替换runnable的方式,因为Thread类的构造方法根本没有Callable.//FutureTask构造可以传递callable//创建FutureTask线程FutureTask futureTask1=new FutureTask<>(new MyThread2());//lambda简化FutureTask线程FutureTask futureTask2=new FutureTask<>(()->{System.out.println(Thread.currentThread().getName()+" in Callable");return 1024;});new Thread(futureTask2,"bb").start();while (!futureTask2.isDone()){System.out.println("wait");}System.out.println(futureTask2.get());System.out.println(futureTask1.get());System.out.println(Thread.currentThread().getName()+" over");}
}

七、辅助类

7.1、减少计数CountDownLatch

CountDownLatch类可以设置一个计数器,然后通过countDown方法来进行减1的操作,使用await方法等待计数器不大于0,然后继续执行await方法之后的语句。

  • CountDownLatch主要有两个方法,当一个或多个线程调用await方法时,这些线程会阻塞
  • 其它线程调用countDown方法会将计数器减1(调用countDown方法的线程不会阻塞)
  • 当计数器的值变为0时,因await方法阻塞的线程会被唤醒,继续执行

案例:6个同学陆续离开教室后才可以关门
正常写法

public class CountDownLatchDemo {public static void main(String[] args) {//6个同学陆续离开教室之后for (int i = 1; i <=6; i++) {new Thread(()->{System.out.println(Thread.currentThread( ).getName()+"号同学离开了教室");},String.valueOf(i)).start();}System.out.println(Thread.currentThread( ).getName()+"锁门了");}
}

会出现问题:
在这里插入图片描述
更改之后:

import java.util.concurrent.CountDownLatch;public class CountDownLatchDemo {public static void main(String[] args) throws InterruptedException {//创建CountDownLatchCountDownLatch countDownLatch=new CountDownLatch(6);//6个同学陆续离开教室之后for (int i = 1; i <=6; i++) {new Thread(()->{System.out.println(Thread.currentThread( ).getName()+"号同学离开了教室");countDownLatch.countDown();},String.valueOf(i)).start();}//等待countDownLatch.await();System.out.println(Thread.currentThread( ).getName()+"锁门了");}
}

在这里插入图片描述

7.2、循环棚栏CyclicBarrier

允许一组线程全部等待彼此达到共同屏障点的同步辅助。循环阻塞在涉及固定大小的线程方的程序中很有用,这些线程必须偶尔等待彼此。屏障被称为循环 ,因为它可以在等待的线程被释放之后重新使用。

例子:集齐7颗龙珠就可以召唤神龙

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;public class CyclicBarrierDemo {//创建固定值private static final int NUMBER = 7;public static void main(String[] args) {CyclicBarrier cyclicBarrier=new CyclicBarrier(NUMBER,()->{System.out.println("已经集齐7颗龙珠,可以召唤神龙了");});for (int i = 1; i <=7; i++) {new Thread(()->{try {System.out.println(Thread.currentThread( ) .getName()+"星龙被收集到了");//等待cyclicBarrier.await();} catch (Exception e) {e.printStackTrace();}},String.valueOf(i)).start();}}
}

在这里插入图片描述

7.3、信号灯Semaphore

一个单向隧道能同时容纳10个小汽车或5个卡车通过(1个卡车等效与2个小汽车), 而隧道入口记录着当前已经在隧道内的汽车等效比重. 比如1个小汽车和1个卡车, 则隧道入口显示3. 若隧道入口显示10表示已经满了. 当汽车驶出隧道之后, 隧道入口显示的数字则会相应的减小. 于这个示例相符合场景非常适合用信号量.

案例:抢车位,6部汽车3个停车位

import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;public class SemaphoreDemo {public static void main(String[] args) {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(new Random().nextInt(5));System.out.println(Thread.currentThread( ) .getName()+"离开了车位");} catch (InterruptedException e) {e.printStackTrace();}finally {semaphore.release();}},String.valueOf(i)).start();}}
}

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...