JUC包(面试常问)

Callable_1">1. Callable接口

类似于Runnable接口,Runnable描述的任务,不带返回值;Callable描述的任务带返回值。

public class Test {
	//创建线程,计算1+2+...+1000
	public static void main(String[] args) throws ExecutionException, InterruptedException {
		//使用Callable定义一个任务
		Callable<Integer> callable = new Callable<Integer>() {
			@Override
			public 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,需要借助futureTask
		Thread t = new Thread(futureTask);
		t.start();
		//获取线程计算结果
		//get方法会阻塞等待直到call方法计算完毕,get才会返回
		System.out.println(futureTask.get());
	}
}

ReentrantLock_31">2. ReentrantLock

和synchronized一样是可重入锁,但是两者又有些不同,可以说reentrantLock是对synchronized的补充。
核心方法

  1. lock()加锁
  2. unlock()解锁
  3. tryLock()尝试加锁
和synchronized相比的缺点

进入synchronized内自动加锁,出了synchronized自动解锁。而reentrantLock需要手动加锁,解锁。这就可能出现解锁失败

public static void main(String[] args) {
	ReentrantLock locker = new ReentrantLock();
	locker.lock();
	if(true) {
		return;
	}
	locker.unlock();
}

上面代码直接return没有执行unlock()方法,解决方法就是使用try finally

public static void main(String[] args) {
	ReentrantLock locker = new ReentrantLock();
	try {
		locker.lock();
		if(true) {
			return;
		}
	} finally {
		locker.unlock();
	}
}

和synchronized相比的优点
  1. tryLock尝试加锁,可以设置加锁等待时间。而synchronized采用的是“死等策略”,死等需要慎重。
  2. ReentrantLock可以实现成公平锁,默认是非公平锁
ReentrantLock locker = new ReentrantLock(true);
  1. synchronized是搭配wait/notify实现等待通知机制,随机唤醒一个等待的线程。ReentrantLock是搭配Condition类实现,可以指定唤醒哪个等待的线程。(实例化多个Condition对象,使用await/signal方法)
面试题:谈谈两者的区别

上面的优点+缺点
补充:synchronized是java关键字,底层是JVM实现的;而ReentrantLock是标准库的一个类,底层基于java实现的

3.原子类

原子类的底层是基于CAS实现的,使用原子类,最常见的场景是多线程计数。例如求服务器有多少并发量。

Semaphore_81">4.信号量Semaphore

信号量相当于一个计数器,表示可用资源的个数。
信号量的基本操作:

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

当计数为0的时候,继续P操作,就会阻塞等待到其他线程V操作。
信号量可用视为一个广义的锁,而锁相当于一个可用资源为1的信号量。

public static void main(String[] args) throws InterruptedException {
	//3个可用资源的信号量
	Semaphore semaphore = new Semaphore(3);
	//P操作,申请一个资源
	semaphore.acquire();
	System.out.println("p操作");
	//V操作释放一个资源
	semaphore.release();
	System.out.println("V操作");
	semaphore.acquire();
	System.out.println("p操作1");
	semaphore.acquire();
	System.out.println("p操作2");
	semaphore.acquire();
	System.out.println("p操作3");
	semaphore.acquire();
	System.out.println("p操作4");

}

image.png
发现“p操作4”没有打印,可用资源只有3,前面已经申请3次了,所以没打印,只能阻塞等待到释放资源。

CountDownLatch_111">5.CountDownLatch

直译过来就是“计数关闭门阀”,很难理解对吧?举个例子马上让你通透。
5名选手进行百米比赛的时候,当最后一个选手撞线比赛才结束。使用CountDownLatch也是类似,每个选手撞线的时候,就调用countDown方法,当撞线次数达到选手个数,就认为比赛结束。
在举个例子,使用多线程下载一个很大的文件,就切分成多个部分,每个线程负责下载一个部分,当一个线程下载完毕,就调用countDown方法,当所有线程都下载完毕,整个文件就下载完毕。

public static void main(String[] args) throws InterruptedException {
	//10个选手参加比赛
	CountDownLatch countDownLatch = new CountDownLatch(5);
	//创建10个线程来执行任务
	for (int i = 0; i < 5; i++) {
		Thread t = new Thread(() -> {
			System.out.println("选手出发" + Thread.currentThread().getName());
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("选手到达" + Thread.currentThread().getName());
			//选手撞线
			countDownLatch.countDown();
		});
		t.start();
	}
	//阻塞等待,直到所有选手都撞线,才能解除阻塞
	countDownLatch.await();
	System.out.println("比赛结束");
}

image.png


http://www.niftyadmin.cn/n/5251786.html

相关文章

LeetCode题:11. 盛最多水的容器

目录 一、题目要求 二、解题思路 三、代码 一、题目要求 11. 盛最多水的容器 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多…

向日葵远程控制鼠标异常的问题

​ 在通过向日葵进行远程控制的时候&#xff0c;可能会遇到鼠标位置异常的问题。此时&#xff0c;不管怎么移动鼠标&#xff0c;都会停留在屏幕最上方&#xff0c;而无法点击到正确的位置。如图&#xff1a; 此时&#xff0c;如果启用了“被控端鼠标”功能&#xff0c;可以正…

计算机视觉-05-目标检测:LeNet的PyTorch复现(MNIST手写数据集篇)(包含数据和代码)

文章目录 0. 数据下载1. 背景描述2. 预测目的3. 数据总览4. 数据预处理4.1 下载并加载数据&#xff0c;并做出一定的预先处理4.2 搭建 LeNet-5 神经网络结构&#xff0c;并定义前向传播的过程4.3 将定义好的网络结构搭载到 GPU/CPU&#xff0c;并定义优化器4.4 定义训练过程4.5…

解密QQ号——C语言

题目&#xff1a; 有一串已加密的数字“6 3 1 7 5 8 9 2 4”解密规则&#xff1a;首先将第1个数字删除&#xff0c;紧接着将第2个数字放到这串数字的末尾&#xff0c;再将第3个数字删除并将第4个数字放到这串数字的末尾&#xff0c;再将第5个数删除 代码实现&#xff1a; #inc…

(七)Python 命令模式

文章目录 1 命令模式简介2 命令模式的特点和目的2.1 命令模式通常使用以下术语:2.1.1 命令模式的UML类图 2.2 命令模式的主要目的如下2.3 命令模式可用于以下各种情景: 3 命令模式python代码示例4 命令模式的优点和缺点4.1 优点4.2 缺点 1 命令模式简介 正如我们在上一章中所看…

简单使用selenium抓取微博热搜话题存储进Excel表格中

#test.pyimport requests from selenium import webdriver import time from write import write#首先打开浏览器 drive webdriver.Chrome()#设置隐式等待&#xff1a;等待元素找到&#xff0c;如果找到元素则马上继续执行语句&#xff0c;如果找不到元素&#xff0c;会在设定…

visual Studio MFC 平台实现拉普拉斯和拉普拉斯与直方图均衡化与中值滤波相结合实现比较

拉普拉斯变换的原理与应用 本文使用visual Studio MFC 平台实现图像增强中的拉普拉斯变换&#xff0c;同时拉普拉斯一般不会单独使用&#xff0c;与其他平滑操作相结合&#xff0c;本文使用了拉普拉斯与直方图均衡化以及与中值滤波相结合&#xff0c;也对三种方式进行了对比 关…

Qt应用开发(Quick篇)——布局类与布局模块

一、前言 实际 应用中&#xff0c;布局是常用的功能&#xff0c;布局最直观的就是提供空间使用率&#xff0c;改善空间的流动和模块之间的重叠&#xff0c;让界面更加的美观。 二、布局类Layout 2.1 介绍 将Layout类型的对象附加到布局的子元素上&#xff0c;提供有关该项的特…