首页 > 其他分享 >显示锁,隐式锁 (管程、monitor 、操作系统)

显示锁,隐式锁 (管程、monitor 、操作系统)

时间:2023-08-03 19:56:07浏览次数:298  
标签:monitor int double 管程 public amount accounts 隐式

无锁时并发出问题

import java.util.*;

/**
 * 无锁
 * @author witas
 *
 */
public class Bank {
    
    
    public static void main(String[] args) {
        
        final int NACCOUNTS = 100;
        final double INITIAL_BALANCE = 1000;
        final double MAX_AMOUNT = 1000;
        final int DELAY = 10;
        
        Bank bank = new Bank(NACCOUNTS, INITIAL_BALANCE);
        for (int i = 0; i < NACCOUNTS; i++) {
            int fromAccount = i;
            Runnable r = () -> {
                try {
                    while (true) {
                        int toAccount = (int) (bank.size() * Math.random());
                        double amount = MAX_AMOUNT * Math.random();
                        bank.transfer(fromAccount, toAccount, amount);
                        Thread.sleep((int) (DELAY * Math.random()));
                    }
                } catch (InterruptedException e) {
                }
            };
            Thread t = new Thread(r,String.format("[线程%3d]", i));
            t.start();
        }
    }
    
    
    private final double[] accounts;

    /**
     * @param n              账户数
     * @param initialBalance 每个账户的余额
     */

    public Bank(int n, double initialBalance) {
        accounts = new double[n];
        Arrays.fill(accounts, initialBalance);
    }

    /**
     * 转账
     * 
     * @param from
     * @param to
     * @param amount 转账金额
     */

    public void transfer(int from, int to, double amount) {
        if (accounts[from] < amount) {
            return;
        }
        accounts[from] -= amount;
        accounts[to] += amount;
        System.out.printf("%s[%2d->%2d,%10.2f][总余额:%10.2f]%n", Thread.currentThread().getName(), from, to, amount, getTotalBalance());
    }

    /**
     * 获取所有账户总余额
     * 
     * @return
     */

    public double getTotalBalance() {
        double sum = 0;
        for (double a : accounts) {
            sum += a;
        }
        return sum;
    }

    /**
     * 获取账户个数
     * 
     * @return
     */
    public int size() {
        return accounts.length;
    }
}

 

通过concurrent 包下工具类可重入锁

import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 显示锁
 * @author witas
 *
 */
public class Bank2 {
    
    
    public static void main(String[] args) {
        
        final int NACCOUNTS = 100;
        final double INITIAL_BALANCE = 1000;
        final double MAX_AMOUNT = 1000;
        final int DELAY = 10;
        
        Bank2 bank = new Bank2(NACCOUNTS, INITIAL_BALANCE);
        for (int i = 0; i < NACCOUNTS; i++) {
            int fromAccount = i;
            Runnable r = () -> {
                try {
                    while (true) {
                        int toAccount = (int) (bank.size() * Math.random());
                        double amount = MAX_AMOUNT * Math.random();
                        bank.transfer(fromAccount, toAccount, amount);
                        Thread.sleep((int) (DELAY * Math.random()));
                    }
                } catch (InterruptedException e) {
                }
            };
            Thread t = new Thread(r,String.format("[线程%3d]", i));
            t.start();
        }
    }
    
    private ReentrantLock lock = new ReentrantLock();
    
    private final double[] accounts;

    /**
     * @param n              账户数
     * @param initialBalance 每个账户的余额
     */

    public Bank2(int n, double initialBalance) {
        accounts = new double[n];
        Arrays.fill(accounts, initialBalance);
    }

    /**
     * 转账
     * 
     * @param from
     * @param to
     * @param amount 转账金额
     */

    public void transfer(int from, int to, double amount) {
        lock.lock();
        try {
            if (accounts[from] < amount) {
                return;
            }
            accounts[from] -= amount;
            accounts[to] += amount;
            System.out.printf("%s[%2d->%2d,%10.2f][总余额:%10.2f]%n", Thread.currentThread().getName(), from, to, amount, getTotalBalance());
        } finally {
            lock.unlock();
        }
    }

    /**
     * 获取所有账户总余额
     * 
     * @return
     */

    public double getTotalBalance() {
        double sum = 0;
        for (double a : accounts) {
            sum += a;
        }
        return sum;
    }

    /**
     * 获取账户个数
     * 
     * @return
     */
    public int size() {
        return accounts.length;
    }
}

 

通过concurrent包下可重入锁和等待条件

import java.util.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 显示锁,带条件
 * @author witas
 *
 */
public class Bank3 {
    
    
    public static void main(String[] args) {
        
        final int NACCOUNTS = 100;
        final double INITIAL_BALANCE = 1000;
        final double MAX_AMOUNT = 1000;
        final int DELAY = 10;
        
        Bank3 bank = new Bank3(NACCOUNTS, INITIAL_BALANCE);
        for (int i = 0; i < NACCOUNTS; i++) {
            int fromAccount = i;
            Runnable r = () -> {
                try {
                    while (true) {
                        int toAccount = (int) (bank.size() * Math.random());
                        double amount = MAX_AMOUNT * Math.random();
                        bank.transfer(fromAccount, toAccount, amount);
                        Thread.sleep((int) (DELAY * Math.random()));
                    }
                } catch (InterruptedException e) {
                }
            };
            Thread t = new Thread(r,String.format("[线程%3d]", i));
            t.start();
        }
    }
    
    private ReentrantLock lock = new ReentrantLock();
    private Condition sufficientFunds = lock.newCondition();
    
    private final double[] accounts;

    /**
     * @param n              账户数
     * @param initialBalance 每个账户的余额
     */

    public Bank3(int n, double initialBalance) {
        accounts = new double[n];
        Arrays.fill(accounts, initialBalance);
    }

    /**
     * 转账
     * 
     * @param from
     * @param to
     * @param amount 转账金额
     * @throws InterruptedException 
     */

    public void transfer(int from, int to, double amount) throws InterruptedException {
        lock.lock();
        try {
            while (accounts[from] < amount) {
                sufficientFunds.await();
            }
            accounts[from] -= amount;
            accounts[to] += amount;
            System.out.printf("%s[%2d->%2d,%10.2f][总余额:%10.2f]%n", Thread.currentThread().getName(), from, to, amount, getTotalBalance());
            sufficientFunds.signalAll();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 获取所有账户总余额
     * 
     * @return
     */

    public double getTotalBalance() {
        double sum = 0;
        for (double a : accounts) {
            sum += a;
        }
        return sum;
    }

    /**
     * 获取账户个数
     * 
     * @return
     */
    public int size() {
        return accounts.length;
    }
}

 

synchronized 表达式

import java.util.Arrays;

/**
 * 隐式锁(statement)
 * @author witas
 *
 */
public class Bank4 {
    
    
    public static void main(String[] args) {
        
        final int NACCOUNTS = 100;
        final double INITIAL_BALANCE = 1000;
        final double MAX_AMOUNT = 1000;
        final int DELAY = 10;
        
        Bank4 bank = new Bank4(NACCOUNTS, INITIAL_BALANCE);
        for (int i = 0; i < NACCOUNTS; i++) {
            int fromAccount = i;
            Runnable r = () -> {
                try {
                    while (true) {
                        int toAccount = (int) (bank.size() * Math.random());
                        double amount = MAX_AMOUNT * Math.random();
                        bank.transfer(fromAccount, toAccount, amount);
                        Thread.sleep((int) (DELAY * Math.random()));
                    }
                } catch (InterruptedException e) {
                }
            };
            Thread t = new Thread(r,String.format("[线程%3d]", i));
            t.start();
        }
    }
    
    private Object lock = new Object();
    
    private final double[] accounts;

    /**
     * @param n              账户数
     * @param initialBalance 每个账户的余额
     */

    public Bank4(int n, double initialBalance) {
        accounts = new double[n];
        Arrays.fill(accounts, initialBalance);
    }

    /**
     * 转账
     * 
     * @param from
     * @param to
     * @param amount 转账金额
     */

    public void transfer(int from, int to, double amount) {
        synchronized(lock) {
            if (accounts[from] < amount) {
                return;
            }
            accounts[from] -= amount;
            accounts[to] += amount;
            System.out.printf("%s[%2d->%2d,%10.2f][总余额:%10.2f]%n", Thread.currentThread().getName(), from, to, amount, getTotalBalance());
        }
    }

    /**
     * 获取所有账户总余额
     * 
     * @return
     */

    public double getTotalBalance() {
        double sum = 0;
        for (double a : accounts) {
            sum += a;
        }
        return sum;
    }

    /**
     * 获取账户个数
     * 
     * @return
     */
    public int size() {
        return accounts.length;
    }
}

 

import java.util.Arrays;

/**
 * 隐式锁(statement),带条件
 * @author witas
 *
 */
public class Bank5 {
    
    
    public static void main(String[] args) {
        
        final int NACCOUNTS = 100;
        final double INITIAL_BALANCE = 1000;
        final double MAX_AMOUNT = 1000;
        final int DELAY = 10;
        
        Bank5 bank = new Bank5(NACCOUNTS, INITIAL_BALANCE);
        for (int i = 0; i < NACCOUNTS; i++) {
            int fromAccount = i;
            Runnable r = () -> {
                try {
                    while (true) {
                        int toAccount = (int) (bank.size() * Math.random());
                        double amount = MAX_AMOUNT * Math.random();
                        bank.transfer(fromAccount, toAccount, amount);
                        Thread.sleep((int) (DELAY * Math.random()));
                    }
                } catch (InterruptedException e) {
                }
            };
            Thread t = new Thread(r,String.format("[线程%3d]", i));
            t.start();
        }
    }
    
    
    private final double[] accounts;
    private Object lock = new Object();

    /**
     * @param n              账户数
     * @param initialBalance 每个账户的余额
     */

    public Bank5(int n, double initialBalance) {
        accounts = new double[n];
        Arrays.fill(accounts, initialBalance);
    }

    /**
     * 转账
     * 
     * @param from
     * @param to
     * @param amount 转账金额
     * @throws InterruptedException 
     */

    public void transfer(int from, int to, double amount) throws InterruptedException {
        synchronized(lock) {
            while (accounts[from] < amount) {
                lock.wait();
            }
            accounts[from] -= amount;
            accounts[to] += amount;
            System.out.printf("%s[%2d->%2d,%10.2f][总余额:%10.2f]%n", Thread.currentThread().getName(), from, to, amount, getTotalBalance());
            lock.notifyAll();
        }
    }

    /**
     * 获取所有账户总余额
     * 
     * @return
     */

    public double getTotalBalance() {
        double sum = 0;
        for (double a : accounts) {
            sum += a;
        }
        return sum;
    }

    /**
     * 获取账户个数
     * 
     * @return
     */
    public int size() {
        return accounts.length;
    }
}

 

synchronized 方法

import java.util.Arrays;

/**
 * 隐式锁(method)
 * @author witas
 *
 */
public class Bank6 {
    
    
    public static void main(String[] args) {
        
        final int NACCOUNTS = 100;
        final double INITIAL_BALANCE = 1000;
        final double MAX_AMOUNT = 1000;
        final int DELAY = 10;
        
        Bank6 bank = new Bank6(NACCOUNTS, INITIAL_BALANCE);
        for (int i = 0; i < NACCOUNTS; i++) {
            int fromAccount = i;
            Runnable r = () -> {
                try {
                    while (true) {
                        int toAccount = (int) (bank.size() * Math.random());
                        double amount = MAX_AMOUNT * Math.random();
                        bank.transfer(fromAccount, toAccount, amount);
                        Thread.sleep((int) (DELAY * Math.random()));
                    }
                } catch (InterruptedException e) {
                }
            };
            Thread t = new Thread(r,String.format("[线程%3d]", i));
            t.start();
        }
    }
    
    
    private final double[] accounts;

    /**
     * @param n              账户数
     * @param initialBalance 每个账户的余额
     */

    public Bank6(int n, double initialBalance) {
        accounts = new double[n];
        Arrays.fill(accounts, initialBalance);
    }

    /**
     * 转账
     * 
     * @param from
     * @param to
     * @param amount 转账金额
     */

    public synchronized void transfer(int from, int to, double amount) {
        if (accounts[from] < amount) {
            return;
        }
        accounts[from] -= amount;
        accounts[to] += amount;
        System.out.printf("%s[%2d->%2d,%10.2f][总余额:%10.2f]%n", Thread.currentThread().getName(), from, to, amount, getTotalBalance());
    }

    /**
     * 获取所有账户总余额
     * 
     * @return
     */

    public double getTotalBalance() {
        double sum = 0;
        for (double a : accounts) {
            sum += a;
        }
        return sum;
    }

    /**
     * 获取账户个数
     * 
     * @return
     */
    public int size() {
        return accounts.length;
    }
}

 

synchronized method wait 

import java.util.Arrays;

/**
 * 隐式锁(method),带条件 
 * @author witas
 *
 */
public class Bank7 {
    
    
    public static void main(String[] args) {
        
        final int NACCOUNTS = 100;
        final double INITIAL_BALANCE = 1000;
        final double MAX_AMOUNT = 1000;
        final int DELAY = 10;
        
        Bank7 bank = new Bank7(NACCOUNTS, INITIAL_BALANCE);
        for (int i = 0; i < NACCOUNTS; i++) {
            int fromAccount = i;
            Runnable r = () -> {
                try {
                    while (true) {
                        int toAccount = (int) (bank.size() * Math.random());
                        double amount = MAX_AMOUNT * Math.random();
                        bank.transfer(fromAccount, toAccount, amount);
                        Thread.sleep((int) (DELAY * Math.random()));
                    }
                } catch (InterruptedException e) {
                }
            };
            Thread t = new Thread(r,String.format("[线程%3d]", i));
            t.start();
        }
    }
    
    
    private final double[] accounts;

    /**
     * @param n              账户数
     * @param initialBalance 每个账户的余额
     */

    public Bank7(int n, double initialBalance) {
        accounts = new double[n];
        Arrays.fill(accounts, initialBalance);
    }

    /**
     * 转账
     * 
     * @param from
     * @param to
     * @param amount 转账金额
     * @throws InterruptedException 
     */

    public synchronized void transfer(int from, int to, double amount) throws InterruptedException {
        while (accounts[from] < amount) {
            this.wait();
        }
        accounts[from] -= amount;
        accounts[to] += amount;
        System.out.printf("%s[%2d->%2d,%10.2f][总余额:%10.2f]%n", Thread.currentThread().getName(), from, to, amount, getTotalBalance());
        this.notifyAll();
    }

    /**
     * 获取所有账户总余额
     * 
     * @return
     */

    public double getTotalBalance() {
        double sum = 0;
        for (double a : accounts) {
            sum += a;
        }
        return sum;
    }

    /**
     * 获取账户个数
     * 
     * @return
     */
    public int size() {
        return accounts.length;
    }
}

 

 

问:synchronized 加锁对象怎么判断?

 答:synchronized 实例方法 是this,synchronized 类方法是当前类,synchronized 表达式是被引用对象。同步方法分为实例方法和静态方法互不干扰,线程请求加锁对象的任意同步方法均需获得锁。

被synchronized 锁定的对象,里面的所有同步方法属一个“管程”(monitor 监视器),理解成所有同步方法会进入到监视器

 

 

问:锁是什么?

答:锁是管程中某线程执行的必要条件 

Monitors an operating system structuring concept.pdf.png 

这是一个附件,把png移除就是pdf文件。

 https://dl.acm.org/doi/pdf/10.1145/355620.361161

 

引申出一个概念“管程”,这是操作系统层面的东西,java 只是实现了这个东西,java的synchronized加锁和解锁是原子操作

管程 (Moniters,也称为监视器)
一.管程的概念
是一种程序结构,结构内的多个子程序(对象或模块)形成的多个工作线程互斥访问共享资源。这些共享资源一般是硬件设备或一群变量。管程实现了在一个时间点,最多只有一个线程在执行管程的某个子程序。
与那些通过修改数据结构实现互斥访问的并发程序设计相比,管程实现很大程度上简化了程序设计。
管程提供了一种机制,线程可以临时放弃互斥访问,等待某些条件得到满足后,重新获得执行权恢复它的互斥访问。即:在管程中的线程可以临时放弃管程的互斥访问,让其他线程进入到管程中来。
管程包含:多个彼此可以交互并共用资源的线程、多个与资源使用有关的变量、一个互斥锁、一个用来避免竞态条件的不变量。
一个管程的程序在运行一个线程前会先取得互斥锁,直到完成线程或是线程等待某个条件被满足才会放弃互斥锁。若每个执行中的线程在放弃互斥锁之前都能保证不变量成立,则所有线程皆不会导致竞态条件成立。
管程是一种高级的同步原语。任意时刻管程中只能有一个活跃进程。它是一种编程语言的组件,所以编译器知道它们很特殊,并可以采用与其他过程调用不同的方法来处理它们。典型地,当一个进程调用管程中的过程,前几条指令将检查在管程中是否有其他的活跃进程。如果有,调用进程将挂起,直到另一个进程离开管程。如果没有,则调用进程便进入管程。
对管程的实现互斥由编译器负责。在Java中,只要将关键字synchronized加入到方法声明中,Java保证一旦某个线程执行该方法,就不允许其他线程执行该方法,就不允许其他线程执行该类中的任何其他方法。
注意:管程是一个编程语言概念。编译器必须要识别出管程并用某种方式对互斥做出安排。C、Pascal及多数其他语言都没有管程,所以指望这些编译器来实现互斥规则是不可靠的。
管程可以看做一个软件模块,它是将共享的变量和对于这些共享变量的操作封装起来,形成一个具有一定接口的功能模块,进程可以调用管程来实现进程级别的并发控制。
进程只能互斥得使用管程,即当一个进程使用管程时,另一个进程必须等待。当一个进程使用完管程后,它必须释放管程并唤醒等待管程的某一个进程。
在管程入口处的等待队列称为入口等待队列,由于进程会执行唤醒操作,因此可能有多个等待使用管程的队列,这样的队列称为紧急队列,它的优先级高于等待队列。
二、管程的特征
1.模块化。
管程是一个基本的软件模块,可以被单独编译。
2.抽象数据类型。
管程中封装了数据及对于数据的操作,这点有点像面向对象编程语言中的类。
3.信息隐藏。
管程外的进程或其他软件模块只能通过管程对外的接口来访问管程提供的操作,管程内部的实现细节对外界是透明的。
4.使用的互斥性。
任何一个时刻,管程只能由一个进程使用。进入管程时的互斥由编译器负责完成。
三、enter过程、leave过程、条件型变量c、wait(c) 、signal(c)
1.enter过程
一个进程进入管程前要提出申请,一般由管程提供一个外部过程--enter过程。如Monitor.enter()表示进程调用管程Monitor外部过程enter进入管程。
2.leave过程
当一个进程离开管程时,如果紧急队列不空,那么它就必须负责唤醒紧急队列中的一个进程,此时也由管程提供一个外部过程—leave过程,如Monitor.leave()表示进程调用管程Monitor外部过程leave离开管程。
3.条件型变量c
条件型变量c实际上是一个指针,它指向一个等待该条件的PCB队列。如notfull表示缓冲区不满,如果缓冲区已满,那么将要在缓冲区写入数据的进程就要等待notfull,即wait(notfull)。相应的,如果一个进程在缓冲区读数据,当它读完一个数据后,要执行signal(notempty),表示已经释放了一个缓冲区单元。
4.wait(c)
wait(c)表示为进入管程的进程分配某种类型的资源,如果此时这种资源可用,那么进程使用,否则进程被阻塞,进入紧急队列。
5.signal(c)
signal(c)表示进入管程的进程使用的某种资源要释放,此时进程会唤醒由于等待这种资源而进入紧急队列中的第一个进程。

 

标签:monitor,int,double,管程,public,amount,accounts,隐式
From: https://www.cnblogs.com/zno2/p/17054817.html

相关文章

  • 如何获取Oracle sql monitor报告
    ql_monitor监控执行时间超过5s的sql,或者开启并行的sql,或者加了/+monitor/的sql,应该是记录实例启动以来的sqlsetlinesize200setpages30colsql_textformata50trunccolinst_idformat99colusernameformata10trunccolsql_idformata14coldate_startformata......
  • 【TrafficMonitor】无法显示13代intel的CPU温度
    原因分析TrafficMonitor的温度检测是利用了第三方软件LibreHardwareMonitor,并且这个问题可能与CPU有关按照作者的指示,我们下载并启动了最新的LibreHardwareMonitor,发现一切正常,cpu温度完全可以正常显示怀疑可能是LibreHardwareMonitor对于我的电脑上CPU做了适配,而TrafficMonit......
  • android隐式启动Activity的例子
    android隐式启动Activity的例子【原创】android2.2测试通过android隐匿启动Activity的例子,同样适用于Service,BroadcastReceiver<activityandroid:name=".MyActivityTwo"android:label="ThisMyActivityTwo"><!--这样进行匹配:Intentintent=newIntent(Intent.ACT......
  • redis monitor 监控说明
    1、监视器Redis监视器是用于监控或观察Redis服务器指令执行的一种特殊的客户端。创建Redis监视器的方式也很简单,启动一个客户端后,执行monitor指令,客户端将进入监视器状态。进入监视器状态的客户端将不再接受Redis指令输入,而称为了一个实时接受服务器指令执行信息的消费者。如下图......
  • ubuntu wifi monitor
    ubuntu安装wifi抓包环境ubuntu安装wifi抓包环境1.wifi型号2.软件安装2.1wifi驱动确认已安装2.2查看wifi信息2.3安装软件3.配置wifi监听模式4.抓包4.1设定channel4.2wireshark过滤器4.3wireshark设置4.4抓包结果1.wifi型号intelAX2002.软件安......
  • 隐式嵌入和无隐式嵌入
    隐式嵌入:==>==>执行的替换是嵌入。既右边表达式的起始位置对应左边表达式的起始位置,结束位置对应结束位置,从而把左边匹配的节点替换成右边的表达式。上图是隐式嵌入执行三次无隐式嵌入:==>>==>>执行的规则类似增加。这个规则没有隐式嵌入,所以右边的表达式中需要有左......
  • 人大金仓学习之四-kmonitor
    人大金仓学习之四-kmonitor背景kmonitor其实时一个很好的工具和思路开元的软件封装一下,减轻技术复杂度,提高部署效率并且能够更加快速的定位解决问题.能够极大的提升客户体验.并且界面比较好看,比kwr看起来高大上多了.不仅可以解决部分实际问题,也可以提高产品的......
  • 25.什么情况下会发生布尔值的隐式强制类型转换
    25.什么情况下会发生布尔值的隐式强制类型转换?(1)if(..)语句中的条件判断表达式。(2)for(..;..;..)语句中的条件判断表达式(第二个)。(3)while(..)和do..while(..)循环中的条件判断表达式。(4)?:中的条件判断表达式。(5)逻辑运算符||(逻辑或)和&&(逻辑与)左边的操作......
  • 如何实现Android 隐式绑定服务的具体操作步骤
    Android隐式绑定服务Android中的服务是一种可以在后台执行长时间运行操作的组件。服务可以在后台运行,即使用户切换到其他应用或锁定设备。在Android中,服务分为两种类型:启动服务和绑定服务。启动服务是通过调用startService()方法来启动的,而绑定服务是通过调用bindService()方法来......
  • 解决Android 修改 Application uiMode monitor dark mode的具体操作步骤
    Android修改ApplicationuiModemonitordarkmode随着智能手机的普及,人们对于移动应用程序的用户界面(UI)的黑暗模式(darkmode)的需求越来越高。黑暗模式不仅能够减少屏幕亮度,保护用户的眼睛,还能节省电池电量,给用户提供更好的用户体验。在Android平台上,我们可以通过修改Applic......