zoukankan      html  css  js  c++  java
  • Java锁对象和条件对象的使用

    锁对象

    临界区:临界区是一个特殊的代码段,该代码段访问某种特殊的公共资源,该资源同一时间只允许一个线程使用。

    Java中可以使用锁对象创造一个临界区:

    1 myLock.lock();
    2 try {
    3     关键代码
    4 } finally {
    5     myLock.unlock();
    6 }

    使用这种结构可以确保关键代码不会同时被多个线程执行,线程想要执行关键代码必须先获取“锁”,“锁”只能被一个线程持有,在该线程将“锁”释放前,其他线程因为获取不到锁而被阻塞,“锁”被释放的时候,之前因为获取这个锁被挂起的线程都会被唤醒,共同竞争着去获取锁。

    将释放锁的操作写在finally里是很重要的,防止某个线程执行关键代码的时候因为抛出异常而没有将锁释放。

     1 package learnspringboot.xiao.learnjava.thread;
     2 
     3 import java.util.HashMap;
     4 import java.util.Map;
     5 import java.util.concurrent.locks.Condition;
     6 import java.util.concurrent.locks.Lock;
     7 import java.util.concurrent.locks.ReentrantLock;
     8 
     9 /**
    10  * @author xzy
    11  * @date 2019-12-13 11:01
    12  * 说明:模拟银行转账
    13  */
    14 public class Bank {
    15     private Map<String, Double> accountMap = new HashMap<>();
    16     private Lock myLock = new ReentrantLock();
    17     private Condition haveMoney = myLock.newCondition();
    18 
    19     public Bank() {
    20         this.accountMap.put("ZhangSan", 100.0);
    21         this.accountMap.put("WangWu", 1000.0);
    22     }
    23 
    24     public void transfer(String from, String to, Double money) {
    25         //线程执行后面的代码段需要先获得锁,获取不到就挂起。
    26         myLock.lock();
    27         System.out.println("当前获得锁的线程:" + Thread.currentThread().getName());
    28         System.out.println(from + "想给" + to + "转" + money + "元," + from + "现在有" + accountMap.get(from) + "元");
    29         try {
    30             while (accountMap.get(from) < money) {
    31                 System.out.println("线程阻塞:" + Thread.currentThread().getName());
    32                 //获取到锁的线程需要等待本条件成立,条件成立前将锁释放,线程阻塞。
    33                 haveMoney.await();
    34             }
    35             accountMap.put(from, accountMap.get(from) - money);
    36             accountMap.put(to, accountMap.get(to) + money);
    37             System.out.println(from + "转给" + to + money + "元  线程:" + Thread.currentThread().getName());
    38             //通知因本条件而挂起的线程,条件现在可能已经满足,可以试着再去获取肯看。
    39             haveMoney.signalAll();
    40         } catch (Exception e) {
    41             e.printStackTrace();
    42         } finally {
    43             myLock.unlock();
    44         }
    45     }
    46 
    47     public static void main(String[] args) {
    48         Bank bank = new Bank();
    49         Thread thread1 = new Thread(() -> {
    50             bank.transfer("ZhangSan", "WangWu", 500.0);
    51         });
    52         Thread thread2 = new Thread(() -> {
    53             bank.transfer("WangWu", "ZhangSan", 1000.0);
    54         });
    55         Thread thread3 = new Thread(() -> {
    56             bank.transfer("ZhangSan", "WangWu", 500.0);
    57         });
    58         thread1.setName("张三给王五500 x1");
    59         thread2.setName("王五给张三1000");
    60         thread3.setName("张三给王五500 x2");
    61         thread1.start();
    62         thread2.start();
    63         thread3.start();
    64         while (true) {
    65 
    66         }
    67     }
    68 }
    View Code

  • 相关阅读:
    AOP-面向切面编程-1
    记一次付工解决Sqlserver问题的过程
    Mysql ---Sqlserver数据迁移到Mysql(Mysql建表迁移数据)
    Mysql ---部署,创建用户
    【C++】C++未定义行为
    【C++】回看面向对象与C++
    【作业】2017级面向对象程序设计——总结作业
    【笔记】Cocos2dx学习笔记
    【个人】绝地求生—吃豆人
    【团队】汇总博客
  • 原文地址:https://www.cnblogs.com/XiaoZhengYu/p/12035248.html
Copyright © 2011-2022 走看看