4月11日java多线程4
继昨天学习了线程池之后,今天学习了多线程内的锁Lock。
定义方法:
ReentrantLock queueLock = new ReentrantLock(); //可重入锁
ReentrantReadWriteLock orderLock = new ReentrantReadWriteLock(); //可重入读写锁
每个锁都有个lock方法(上锁)和unlock方法(释放锁)
在写入锁的时候只能有一个线程,但是读取锁的时候可以线程一起共享锁里面的代码
今天还学习了信号量Semphore 自己定义最大可以同时运行多少线程
定义方法:
Semaphore placeSemaphore = new Semaphore(5);
使用acquire方法获得信号量 总信号量-1
使用release方法释放信号量 总信号量+1
附今日的代码:
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; public class LockExample { private static final ReentrantLock queueLock = new ReentrantLock(); //可重入锁
private static final ReentrantReadWriteLock orderLock = new ReentrantReadWriteLock(); //可重入读写锁 /**
* 有家奶茶店,点单有时需要排队
* 假设想买奶茶的人如果看到需要排队,就决定不买
* 又假设奶茶店有老板和多名员工,记单方式比较原始,只有一个订单本
* 老板负责写新订单,员工不断地查看订单本得到信息来制作奶茶,在老板写新订单时员工不能看订单本
* 多个员工可同时看订单本,在员工看时老板不能写新订单
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
//buyMilkTea();
handleOrder(); //需手动关闭
} public void tryToBuyMilkTea() throws InterruptedException {
boolean flag = true;
while(flag)
{
//判断queneLock现在是什么状态,如果是锁住的状态就返回false,如果是空闲状态则将它锁住返回true。
if (queueLock.tryLock()) {
//queueLock.lock();
//随机睡眠一段时间
long thinkingTime = (long) (Math.random() * 500);
Thread.sleep(thinkingTime);
System.out.println(Thread.currentThread().getName() + ": 来一杯珍珠奶茶,不要珍珠");
flag = false;
//将锁释放
queueLock.unlock();
} else {
//System.out.println(Thread.currentThread().getName() + ":" + queueLock.getQueueLength() + "人在排队");
System.out.println(Thread.currentThread().getName() + ": 再等等");
}
if(flag)
{
Thread.sleep(1000);
}
} } public void addOrder() throws InterruptedException {
//写入锁 锁住的情况下只能一个线程写
orderLock.writeLock().lock();
//睡眠一段时间
long writingTime = (long) (Math.random() * 1000);
Thread.sleep(writingTime);
System.out.println("老板新加一笔订单");
//释放锁
orderLock.writeLock().unlock();
} public void viewOrder() throws InterruptedException {
//读取锁 锁住的情况下可以多个线程一起共享
orderLock.readLock().lock();
//睡眠一段时间
long readingTime = (long) (Math.random() * 500);
Thread.sleep(readingTime);
System.out.println(Thread.currentThread().getName() + ": 查看订单本");
//释放锁
orderLock.readLock().unlock(); } //买奶茶方法
public static void buyMilkTea() throws InterruptedException {
LockExample lockExample = new LockExample();
//定义线程数
int STUDENTS_CNT = 10;
//建立线程
Thread[] students = new Thread[STUDENTS_CNT];
for (int i = 0; i < STUDENTS_CNT; i++) {
//给每个线程完成初始化
students[i] = new Thread(new Runnable() { @Override
public void run() {
try {
//随机睡眠一段时间
long walkingTime = (long) (Math.random() * 1000);
Thread.sleep(walkingTime);
//尝试现在是否能够买奶茶
lockExample.tryToBuyMilkTea();
} catch(InterruptedException e) {
System.out.println(e.getMessage());
}
} }
);
//让所有线程开始工作
students[i].start();
} for (int i = 0; i < STUDENTS_CNT; i++)
//等待所有线程结束
students[i].join(); } public static void handleOrder() throws InterruptedException {
LockExample lockExample = new LockExample(); //创建了一个老板写的线程类并且完成了初始化。
Thread boss = new Thread(new Runnable() { @Override
public void run() {
while (true) {
try {
//添加订单
lockExample.addOrder();
//随机睡眠一段时间
long waitingTime = (long) (Math.random() * 1000);
Thread.sleep(waitingTime);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
}
});
//老板线程开始
boss.start();
//定义员工线程数
int workerCnt = 3;
//创建员工线程
Thread[] workers = new Thread[workerCnt];
for (int i = 0; i < workerCnt; i++)
{
//给每个员工线程初始化
workers[i] = new Thread(new Runnable() { @Override
public void run() {
while (true) {
try {
//查看订单
lockExample.viewOrder();
//睡眠一段时间
long workingTime = (long) (Math.random() * 5000);
Thread.sleep(workingTime);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
} });
//员工线程开始工作
workers[i].start();
} }
}
import java.util.concurrent.Semaphore; public class SemaphoreExample {
//定义了5个车位
private final Semaphore placeSemaphore = new Semaphore(5); public boolean parking() throws InterruptedException {
//如果此时Semaphore信号量不为0就会获取一个信号量返回true并且信号量-1,如果信号量为0的话则返回false
if (placeSemaphore.tryAcquire()) {
System.out.println(Thread.currentThread().getName() + ": 停车成功");
return true;
} else {
System.out.println(Thread.currentThread().getName() + ": 没有空位");
return false;
} } public void leaving() throws InterruptedException {
//释放掉一个信号量,信号量+1
placeSemaphore.release();
System.out.println(Thread.currentThread().getName() + ": 开走");
} /**
* 现有一地下车库,共有车位5个,由10辆车需要停放,每次停放时,去申请信号量
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
//定义总共要停车的数量
int tryToParkCnt = 10; SemaphoreExample semaphoreExample = new SemaphoreExample();
//创建要停车的数量的线程
Thread[] parkers = new Thread[tryToParkCnt]; for (int i = 0; i < tryToParkCnt; i++) {
//将每个线程进行初始化
parkers[i] = new Thread(new Runnable() {
//这是视频里面的源代码,我在运行之后发现结果和我想象中的有点不同,因为有的车没有停到车位,不是等待之后再停车,而是直接没有停车了。
//原因是不管if里面返回true或是false都只会执行一次,如果是false的话就只输出了一个没有空位,然后线程就结束了。
//所以我在if判断的外面加了一个while死循环,当if为true,车成功的停车然后离开车位之后break退出循环。
// @Override
// public void run() {
// try {
// long randomTime = (long) (Math.random() * 1000);
// Thread.sleep(randomTime);
// if (semaphoreExample.parking()) {
// long parkingTime = (long) (Math.random() * 1200);
// Thread.sleep(parkingTime);
// semaphoreExample.leaving();
// }
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
@Override
public void run() {
try {
exit:
while(true)
{
//睡眠一段时间
long randomTime = (long) (Math.random() * 1000);
Thread.sleep(randomTime);
//尝试进行停车,如果停车成功会返回true
if (semaphoreExample.parking()) {
//睡眠一段时间,然后调用离开方法
long parkingTime = (long) (Math.random() * 1200);
Thread.sleep(parkingTime);
semaphoreExample.leaving();
break exit;
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
//让每个线程开始工作
parkers[i].start();
} for (int i = 0; i < tryToParkCnt; i++) {
//等待每个线程结束
parkers[i].join();
}
}
}
4月11日java多线程4的更多相关文章
- 4月10日java多线程3
在之前我学习了java中的Thread 来实现多线程,今日我学习了ThreadGroup.Executor框架.ForkJoin框架.Executor 和ForkJoin都可以直接定义线程池,可以根据 ...
- IT培训行业变革大会,7月11日启程!
自上世纪八十年代PC时代起,IT行业走过了以2G移动网络和宽带网络.PC终端为主要载体,软件产品.应用软件和门户网站为特征产品的PC互联网时代. 以3/4G移动和高速宽带和移动终端为主要载体,移动支付 ...
- 4月11日 python学习总结 对象与类
1.类的定义 #类的定义 class 类名: 属性='xxx' def __init__(self): self.name='enon' self.age=18 def other_func: pas ...
- 【视频】k8s套娃开发调试dapr应用 - 在6月11日【开源云原生开发者日】上的演示
这篇博客是在2022年6月11日的[开源云原生]大会上的演讲中的演示部分.k8s集群套娃(嵌套)是指在一个k8s的pod中运行另外一个k8s集群,这想法看上去很疯狂,实际上非常实用. k8s集群套娃( ...
- Yoshua Bengio 2016年5月11日在Twitter Boston的演讲PPT
Yoshua Bengio最新演讲:Attention 让深度学习取得巨大成功(46ppt) Yoshua Bengio,电脑科学家,毕业于麦吉尔大学,在MIT和AT&T贝尔实验室做过博士后研 ...
- 2015年12月28日 Java基础系列(六)流
2015年12月28日 Java基础系列(六)流2015年12月28日 Java基础系列(六)流2015年12月28日 Java基础系列(六)流
- 8月11日嵌入式Linux开发免费项目体验邀您参与
嵌入式Linux开发免费项目体验开课啦~~我们特意邀请到粤嵌金牌讲师和技术专家,为大家带来精彩有趣的嵌入式公开课,涉及到嵌入式学习.研发的方方面面.课堂中我们能体验到的不仅仅是最新资讯.技术体验,还有 ...
- 2016年12月11日 星期日 --出埃及记 Exodus 21:6
2016年12月11日 星期日 --出埃及记 Exodus 21:6 then his master must take him before the judges. He shall take hi ...
- 2016年11月11日 星期五 --出埃及记 Exodus 20:2
2016年11月11日 星期五 --出埃及记 Exodus 20:2 "I am the LORD your God, who brought you out of Egypt, out o ...
随机推荐
- PHP 中的Trait
概述 在PHP中有一种代码复用的技术, 因为单继承的问题, 有些公共方法无法在父类中写出, 而 Trait可以应对这种情况, 它可以定义一些复用的方法, 然后在你需要使用的类中将其引入即可. 刚开始的 ...
- Vue移动端项目模板
一个集成移动端开发插件的Vue移动端模板包含1.css: 使用stylus开发css 集成reset样式文件 修改UI组件文件 统一样式处理(如主题色等)2.UI组件 使用热门的vant与mint-u ...
- python 的with用途(清理资源和异常处理,同时代码精简)
参考如下博客. https://www.cnblogs.com/DswCnblog/p/6126588.html #!/usr/bin/env python # with_example02.py c ...
- 调用android的getColor()方法出现 java.lang.NoSuchMethodError: android.content.res.Resources.getColor
1.java.lang.NoSuchMethodError: android.content.res.Resources.getDrawable/getColor或者 java.lang.NoSuch ...
- C语言使用HZK16显示每个像素的代码
下边内容段是关于C语言使用HZK16显示每个像素的内容. #include<stdio.h>#include<stdlib.h>void main(){ int i,j; ch ...
- QT解析和组装json
json这个小朋友熟悉又陌生,今天给同学们好好讲讲QT是如何使用json的,一句话:简单 1.什么是json? A:json就是个<key,value>字符串 ①一个json对象 {&qu ...
- 用 Heapster 监控集群 - 每天5分钟玩转 Docker 容器技术(176)
Heapster 是 Kubernetes 原生的集群监控方案.Heapster 以 Pod 的形式运行,它会自动发现集群节点.从节点上的 Kubelet 获取监控数据.Kubelet 则是从节点上的 ...
- 不能收缩 ID 为 %s 的数据库中 ID 为 %s 的文件,因为它正由其他进程收缩或为空。
SQLServer数据库通常都不建议进行SHRINKFILE操作,因为SHRINKFILE不当会造成一定的性能问题. 但是当进行了某些操作(例如某个超大的日志类型表转成分区表切换了数据文件),数据库某 ...
- Linux学习历程——Centos 7 tar命令
一.命令介绍 tar命令用于对文件进行打包压缩或解压. tar常用参数 参数 作用 -c 创建压缩文件 -x 解开压缩文件 -t 查看压缩包内有哪些文件 -r 向压缩归档末尾追加文件 -u 更新压缩包 ...
- Vue-Router模式、钩子
转:https://www.cnblogs.com/heioray/p/7193841.html 模式 vue-router中的模式选项主要在router实例化的时候进行定义的,如下 const ro ...