一、Lock()锁
1.1 Lock()的基本介绍:
- 从JDK 5.0开始,Java就提供了更加强大的线程同步机制 — — 通过显示定义同步锁对象来实现同步。
- java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。
- ReentrantLock 类实现了 Lock ,它拥有与synchronized 相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显式加锁、释放锁。
1.2 公式图:

Lock(锁)公式
1.3 代码演示:
package com.atguigu.exer;
import java.util.concurrent.locks.ReentrantLock;
/**
* 解决线程安全问题的方式三:Lock锁 --- JDK5.0新增
*
* 1.面试题:synchronized 与 Lock 的异同?
* 相同:都是解决线程的安全问题。
* 不同:synchronized机制在执行完相应的同步代码以后,自动释放同步监视器。
* lock需要手动启动同步(lock()方法),同时结束同步也需要手动释放同步监视器(unlock()方法)。
*
* 2.优先使用顺序:
* Lock 同步代码块(已经进入了方法体,分配了相应资源) 同步方法
* (在方法体之外)
*
* 3.面试题:如何解决线程安全问题?有几种方式
*
* @author czh
* @create 2020-03-23-22:02
*/
class WTest implements Runnable{
private int ticket = 100;
//1.实例化ReentrantLock
private ReentrantLock lock = new ReentrantLock(true);
@Override
public void run() {
while (true){
try {//2.1
//2.2调用锁定方法:lock()
lock.lock();
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖票:票号为:" + ticket);
ticket--;
} else {
break;
}
} finally {
//3.调用解锁的方法:unlock()
lock.unlock();
}
}
}
}
public class Test {
public static void main(String[] args) {
WTest wTest = new WTest();
Thread t1 = new Thread(wTest);
Thread t2 = new Thread(wTest);
Thread t3 = new Thread(wTest);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
二、线程同步的练习题 ①

2.1 代码演示:
package com.atguigu.exer;
/**
* 银行有一个账户。
* 有两个储户分别向同一个账户存3000元,
* 每次存1000,存3次。每次存完打印账户余额。
*
* 分析:
* 1.是否是多线程问题? 是,一个账户,两个储户使用。
* 2.是否有共享数据? 有,储户的余额。
* 3.是否有线程安全问题? 有。
* 4.考虑如何解决线程安全问题? 同步机制(三种方法)。
*
* @author czh
* @create 2020-03-23-22:02
*/
class Accountt{//创建银行账户
private double balance;
//构造器快捷键:alt + insert
public Accountt(double balance) {
this.balance = balance;
}
//存钱
//这里用继承来同步,默认使用了this
//但是该方法在account下,所以还是安全的
public synchronized void depositt(double amt){
if (amt>0) {
balance += amt;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "存钱成功。余额为:" + balance);
}
}
}
class Customerr extends Thread{//储户
private Accountt acctt;
//alt + insert
public Customerr(Accountt acctt) {
this.acctt = acctt;
}
@Override
public void run() {
for (int i = 0; i < 3; i++) {
acctt.depositt(1000);
}
}
}
public class Test {
public static void main(String[] args) {
Accountt accountt = new Accountt(0);
Customerr t1 = new Customerr(accountt);
Customerr t2 = new Customerr(accountt);
t1.setName("甲");
t2.setName("乙");
t1.start();
t2.start();
}
}