JavaEE传送门

JavaEE

JavaEE——常见的锁策略

JavaEE——CAS


目录

  • JUC
    • 1. Callable 接口
    • 2. ReentrantLock
    • 3. 原子类
    • 4. 线程池
    • 5. 信号量 Semaphore
    • 6. CountDownLatch

JUC

JUC 全称 java.util.concurrent

1. Callable 接口

类似于 Runnable. Runnable 描述的任务, 不带返回值. Callable 描述的任务是带返回值的.

示例: 创建线程, 通过线程来计算 1 + 2 + 3 + . . . + 1000

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class Test {public static void main(String[] args) throws ExecutionException, InterruptedException {//使用 callable 定义一个任务Callable<Integer> callable = new Callable<Integer>() {@Overridepublic Integer call() throws Exception {int sum = 0;for(int i = 1; i <= 1000; i++) {sum += i;}return sum;}};//存在的意义, 就是为了我们能够获取到结果(获取到结果的凭证)FutureTask<Integer> futureTask = new FutureTask<>(callable);//创建线程来执行上述任务//Thread 的构造方法, 不能直接传 callable , 还需要一个中间的类Thread t = new Thread(futureTask);t.start();//获取线程的计算结果//get 方法会阻塞, 直到 call 方法计算完毕, get 才会返回System.out.println(futureTask.get());}
}

总结: 线程创建的方式

  1. 继承 Thread
  2. 实现 Runnable
  3. 使用 lambda
  4. 使用线程池
  5. 使用 Callable

2. ReentrantLock

可重入互斥锁. 和 synchronized 定位类似, 都是用来实现互斥效果, 保证线程安全.

核心用法:

  1. lock( ): 加锁, 如果获取不到锁就死等
  2. tryLock(超时时间): 加锁, 如果获取不到锁, 等待一定时间之后就放弃加锁
  3. unlock( ): 解锁

小缺点

import java.util.concurrent.locks.ReentrantLock;public class Demo1 {public static void main(String[] args) {ReentrantLock locker = new ReentrantLock();//加锁locker.lock();//解锁locker.unlock();}
}

在上述代码中, 如果在 locker.lock();locker.unlock(); 之间, 出现了 return, 或者有异常, 就可能导致 unlock 执行不了.

解决方案: 使用try finally

import java.util.concurrent.locks.ReentrantLock;public class Demo1 {public static void main(String[] args) {ReentrantLock locker = new ReentrantLock();try{//加锁locker.lock();}finally {//解锁locker.unlock();}}
}

优势

ReentrantLock 有一些特定的功能, 是 sychronized 做不到的.

  1. tryLock 试试看能不能加上锁. 成功了, 就加锁成功. 试失败了, 就放弃. 并且还可以指定加锁的等待超时时间.

  2. ReentrantLock 可以实现 公平锁. (默认是非公平的), 构造的时候,传入一个简单的参数, 就成了公平锁.

    ReentrantLock locker = new ReentrantLock(true);
    
  3. sychornized 是搭配 wait/ notify 实现等待通知机制的, 唤醒操作是一个随机的过程.

    ReentrantLock 是搭配 Condition 类实现的, 可以指定唤醒哪一个等待的线程.


3. 原子类

原子类的底层, 是基于 CAS 实现的, Java 里面已经封装好了, 可以直接来使用.

使用原子类, 最常见的场景就是多线程计数, 写了个服务器, 服务器一共有多少并发量, 就可以通过这样的原子变量来累加.

示例

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;public class Test {public static void main(String[] args) throws InterruptedException {AtomicInteger count = new AtomicInteger(0);Thread t1 = new Thread(() -> {for (int i = 0; i < 50000; i++) {// 相当于 count++count.getAndIncrement();/*// 相当于 ++countcount.incrementAndGet();// 相当于 count--count.getAndDecrement();// 相当于 count--count.decrementAndGet();*/}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50000; i++) {// 相当于 count++count.getAndIncrement();}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);}
}

运行结果展示


4. 线程池

JavaEE——No.2 多线程案例(内含线程池)

JavaEE——线程小知识(线程和线程池的好处)


5. 信号量 Semaphore

信号量的基本操作是两个:

  1. P 操作, 申请一个资源
  2. V操作, 释放一个资源

信号量本身是一个计数器, 表示可用资源的个数.

  • P 操作申请一个资源, 可用资源就 -1
  • V 操作释放一个资源, 可用资源就 +1
  • 当计数为 0 的时候, 继续 P 操作, 就会产生阻塞等待, 阻塞等待到其他线程 V 操作了为止.

信号量可以视为是一个更广义的锁, 锁就是一个特殊的信号量 (可用资源只有 1 的信号量)

我们把互斥锁也看做是计数为 1 的信号量.(取值只有 1 和 0, 也叫做 二元信号量)

Java 标注库提供了 Semaphore , 这个类, 其实就是把 操作系统 提供的信号量封装了一下.

示例

import java.util.concurrent.Semaphore;public class Test {public static void main(String[] args) throws InterruptedException {// 构造的时候需要指定初始值, 计数器的初始值, 表示有几个可用资源Semaphore semaphore = new Semaphore(4);// P 操作, 申请资源, 计数器 - 1semaphore.acquire();System.out.println("P 操作");semaphore.acquire();System.out.println("P 操作");semaphore.acquire();System.out.println("P 操作");semaphore.acquire();System.out.println("P 操作");semaphore.acquire();System.out.println("P 操作");// V 操作, 申请资源, 计数器 + 1semaphore.release();System.out.println("V 操作");}
}

上述代码中, 我们在只有 4 个可用资源的前提下, 进行了 5次 P 操作, 会发生什么呢?

我们发现, 进行了 4次 P操作 之后, 就开始阻塞等待, 这个阻塞会一直阻塞下去, 直到有人进行 V操作.

# 注意 #

当需求中, 有多个可用资源的时候, 要记得使用信号量.


6. CountDownLatch

同时等待 N 个任务执行结束.

好像跑步比赛,10个选手依次就位,哨声响才同时出发;所有选手都通过终点,才结束比赛.

使用 CountDownLatch 就是类似的效果, 使用时先设置有几个选手, 选手撞线的时候, 就调用一下 CountDownLatch 方法, 当撞线次数达到了选手的个数, 就认为比赛结束了.

示例

import java.util.concurrent.CountDownLatch;public class CountDownLatch1 {public static void main(String[] args) throws InterruptedException {// 有 10 个选手参加了比赛CountDownLatch countDownLatch = new CountDownLatch(10);for(int i = 0; i < 10; i++){//创建 10 个线程来执行一批任务Thread t = new Thread(() -> {System.out.println("选手出发! " + Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("选手到达! "  + Thread.currentThread().getName());//撞线countDownLatch.countDown();});t.start();}//await 是进行阻塞等待, 会等到所有选手都撞线之后, 才结束阻塞countDownLatch.await();System.out.println("比赛结束! ");}
}

运行结果展示


JavaEE——JUC相关推荐

  1. 【JAVAEE】JUC(java.util.concurrent)的常见类

    目录 1.Callable接口 1.1简介 1.2代码演示 1.3Runnable与Callable的区别 2.ReentrantLock 2.1ReentrantLock的常用方法 2.2Reent ...

  2. Java高频面试题(2022) - Java、Mysql、JUC、JVM、SSM

    目录 不好使!点右边小目录定位: 目录 JavaSE HashMap底层原理?★★ Vector.ArryList.LinkedList 的区别与联系 Hashtable与HashMap的区别?如何解 ...

  3. 面试高频——JUC并发工具包快速上手(超详细总结)

    目录 一.什么是JUC 二.基本知识 2.1.进程和线程 2.2.Java默认有两个进程 2.3.Java能够开启线程吗? 2.4.并发和并行 2.5.线程的状态 2.6.wait和sleep的区别 ...

  4. 为经典版eclipse增加web and JavaEE插件

    为经典版eclipse增加web and JavaEE插件 为经典版eclipse增加web and JavaEE插件 方法/步骤 在Eclipse中菜单help选项中选择install new so ...

  5. JavaEE程序员必读图书大推荐 .

    下面是我根据多年的阅读和实践经验,给您推荐的一些图书: 第一部分: Java语言篇 1 <Java编程规范> 星级: 适合对象:初级,中级 介绍:作者James Gosling(Java之 ...

  6. JUC 常用 4 大并发工具类

    欢迎关注方志朋的博客,回复"666"获面试宝典 什么是JUC? JUC就是java.util.concurrent包,这个包俗称JUC,里面都是解决并发问题的一些东西 该包的位置位 ...

  7. JUC AQS ReentrantLock源码分析

    Java的内置锁一直都是备受争议的,在JDK 1.6之前,synchronized这个重量级锁其性能一直都是较为低下,虽然在1.6后,进行大量的锁优化策略,但是与Lock相比synchronized还 ...

  8. java美容美发项目下载_基于jsp的美容美发管理-JavaEE实现美容美发管理 - java项目源码...

    基于jsp+servlet+pojo+mysql实现一个javaee/javaweb的美容美发管理, 该项目可用各类java课程设计大作业中, 美容美发管理的系统架构分为前后台两部分, 最终实现在线上 ...

  9. JavaEE路径陷阱之getRealPath

    转自:http://blog.csdn.net/shendl/article/details/1427637   JavaEE路径陷阱之getRealPath 本文是<Java路径问题最终解决方 ...

最新文章

  1. js获取当前浏览器地址栏的链接,然后在链接后面加参数
  2. 卷积神经网络——本质上是在利用卷积做特征压缩,然后再全连接
  3. tableau应用实战案例(四十八)-以可视化的形式打开目标跟踪
  4. 机器学习第3天:多元线性回归
  5. python写入一个文件之前可以不打开_如何用python实现真正的打开和关闭文件
  6. Serverless在游戏运营行业进行数据采集分析的最佳实践 链接:
  7. 将java 打包成exe 可执行文件
  8. java8 从数组获取流_从数组到流再到Java 8
  9. 使用MonkeyTest对Android客户端进展压力测试
  10. python老齐_python-basic
  11. MS509Team----------------Cknife
  12. if语句 power query_判断(if)语句
  13. python 解压zip ,rar 文件及编译错误的解决方法
  14. 【ansys workbench】19.力学计算对比学习
  15. visio 2007 画直线和矩形
  16. 定位神器:1秒定位DOM元素绑定的事件代码的位置
  17. 淘宝直通车关键数据 如何利用直通车获取手淘搜索流量 如何利用定向操作获得猜你喜欢流量
  18. PHP开发微信支付小微商户V3版本 图片上传、生成签名、平台证书获取、平台证书编号、敏感信息加密
  19. 不知道买啥绘本?适合3-6岁儿童的绘本书单,建议父母收藏
  20. web前端框架开发实例,html5元素大全

热门文章

  1. 论文投稿指南——中文核心期刊推荐(科学、科学研究)
  2. Tkinter Treeview tag_configure失效问题
  3. 目标检测中的Anchor
  4. Core Data 详解
  5. 小程序微信支付功能开发
  6. Revit快速标注 | 有求必应的【万能标注】操作步骤
  7. Franka Emika Panda连接真实机械臂(一)
  8. pycharm快速注释快捷键
  9. UE4-SubSystem
  10. 一个项目的基本要素都有哪些?