想法来源
在学习操作系统时学到用pv操作解决进程的互斥和同步问题,我就想用java中有多线程,是不是也可以用它来代替synchronized同步块解决部分同步问题,结果就有了下面的东西。
pv操作学习
有兴趣可以去看看b站操作系统的25-29集
先自己写一个pv工具类
package p1;
/**
* 模拟P-V的工具类解决线程的互斥和同步问题
* 不使用synchronized关键字
* 这里的队列我就用java自己的线程队列 之前用自己写的线程队列,出现了线程同步问题
* 有点复杂,自己没解决
*/
public class PVUtil {
//用于计数
private int count;
public PVUtil(int count){
this.count = count;
}
/**
* 模拟Passeren
*/
public synchronized void P() throws InterruptedException {
//让value自减小
count--;
if(count >= 0){
return ;
}else{
this.wait();
}
}
/**
* 模拟Vrijgwven
*/
public synchronized void V(){
count++;
if(count > 0){
return ;
}else{
this.notify();
}
}
}
然后是互斥问题的解决
package p1;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 测试用PV工具类解决线程互斥
* 线程互斥指的是两个线程访问同一份独占性资源,必须协调他们的存储顺序
* 我这里要做的是多个用户取钱的互斥问题
*/
public class TestPVMutex {
static PVUtil pv = new PVUtil(1);
/**
* 模拟多个用户在同一个账号取钱存在延迟的操作
*/
public static void main(String[] args) {
//一份资源
Account account = new Account(1000);
AtomicInteger integer = new AtomicInteger(1);
//多个用户
Thread thread1 = new WithDrawMoney(account);
Thread thread2 = new WithDrawMoney(account);
Thread thread3 = new WithDrawMoney(account);
Thread thread4 = new WithDrawMoney(account);
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
/**
* 模拟取钱
*/
class WithDrawMoney extends Thread{
private Account account;
public WithDrawMoney(Account account){
this.account = account;
}
@Override
public void run() {
//为线程加上pv,用于解决互斥问题
//这里表示我要使用资源,独占
try {
TestPVMutex.pv.P();
} catch (InterruptedException e) {
e.printStackTrace();
}
int value = account.money - 800;
if(value < 0){
System.out.println("账户余额不足...无法取出");
}else{
//模拟延迟
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//取钱
account.money -= 800;
System.out.println("取走800元,账户余额:" + account.money + "元");
}
//表示我用爽了,你们用吧
TestPVMutex.pv.V();
}
}
/**
* 一个账户
*/
class Account{
/**
* 账户余额
*/
int money;
public Account(int money){
this.money = money;
}
}
分析
没有加入pv操作产生的互斥问题 很明显不合理
加入pv操作后
然后用pv操作解决同步问题
package p1;
/**
* 使用PV解决线程同步的问题
* 同步问题:一个线程要做某一个操作时需要另外一个线程做某一个操作后才可以做
* 比如我这里要做的是公交车司机和售票员的例子,司机要等售票员关门才可以发动,售票员要等司机
* 停下车才可以开门,如果不做同步处理,就乱套了
*/
public class TestPVSychronized {
static PVUtil pv1 = new PVUtil(0);
static PVUtil pv2 = new PVUtil(0);
public static void main(String[] args) {
Thread driver = new Driver();
Thread conductor = new Conductor();
driver.start();
conductor.start();
}
}
/**
* 司机
*/
class Driver extends Thread{
@Override
public void run() {
//判断门是否关闭
try {
TestPVSychronized.pv1.P();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("起动了。。。坐好了");
System.out.println("行驶中。。。开车中。。");
System.out.println("停车了。。。");
//通知车停下来
TestPVSychronized.pv2.V();
}
}
/**
* 售票员
*/
class Conductor extends Thread{
@Override
public void run() {
System.out.println("我tm直接把门一关");
//通知我把门关了
TestPVSychronized.pv1.V();
System.out.println("都tm给我买票");
//判断车是否停止
try {
TestPVSychronized.pv2.P();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("停车了,都tm下车");
}
}
没有加入pv顺序会乱
加入pv后