锁对象

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

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