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();
}
}
}
上一篇:HDU 1698——Just a Hook——————【线段树区间替换、区间求和】


下一篇:HDU 1698 just a hook - 带有lazy标记的线段树(用结构体实现)