目录
为什么会有锁?
锁是作为并发共享数据,保证一致性的工具。例如我们的买票,当我们去创建多个线程去买票时,如果不加锁那必然会对资源造成紊乱。
接下来我们会依据这个买票的模型去探讨这个锁。
无锁造成资源的混乱
我先写一个简单的买票事件。
Ticket票类,其中定义票的个数。
public class Ticket {
int ticket = 100;
}
User类就是我们的线程类,调用run方法去进行购票
public class User extends Thread{
Ticket tk;
public User(Ticket tk){
this.tk = tk;
}
public void run(){
while(tk.ticket > 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//同步代码块
//synchronized (tk) {
System.out.println(this.getName() + "买到了" + tk.ticket-- + "号票!");
//}
}
}
}
再去一个Main类,就是我们的测试类,去创建多个线程对象然后执行。
public class Main {
public static void main(String[] args){
Ticket tk = new Ticket();
User A = new User(tk);
User B = new User(tk);
User C = new User(tk);
A.start();
B.start();
C.start();
}
}
我们来显示一下运行结果。

显而易见,必定出现多个线程买到同样的票数。那这样就不符合我们的买票的机制了
这个时候我们就需要去加入sychronized锁,这样的同步代码块,这个锁的作用是只允许一个线程去调用,当一个线程加入sychronized锁时就会从Runnable状态进入Blocked状态
加入sychronized锁后
public class User extends Thread{
Ticket tk;
public User(Ticket tk){
this.tk = tk;
}
public void run(){
while(tk.ticket > 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//同步代码块
synchronized (tk) {
System.out.println(this.getName() + "买到了" + tk.ticket-- + "号票!");
}
}
}
}
注意:synchronized(同步监听器(锁)){
同步代码块。。。
}
所有的对象都是一个同步监视器(锁)
在多线程中使用的同步监听器必须是同一个。
效果展示:

这个时候,我们就能发现,每次买到的票都是不重复的。
Lock手动锁
当然我们除了加synchronized锁之外,我们也可以去手动的加锁,然后手动的去释放掉锁
我们给出代码
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class User implements Runnable{
Ticket tk;
Lock lock = new ReentrantLock();
public User(Ticket tk){
this.tk = tk;
}
@Override
public void run() {
while (tk.ticket > 0){
System.out.println(Thread.currentThread().getName()+":");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//mp();
//手动加锁
lock.lock();
System.out.println(Thread.currentThread().getName()+"买到了"+tk.ticket--+"号票!");
//释放
lock.unlock();
}
}
public synchronized void mp(){
System.out.println(Thread.currentThread().getName()+"买到了"+tk.ticket--+"号票!");
}
}
结果也是与加synchronized锁相同的,这里只需要看改变User这个类,其他的Ticket类,Main类都是一样的。
好了,这就是简单的介绍这两种锁来实现我们的线程安全的问题。
大家也考虑一下银行取钱的问题来保证线程安全。
本文介绍了并发编程中锁的重要性,通过买票和银行取款案例阐述了无锁状态导致的资源混乱,展示了`synchronized`和`ReentrantLock`两种锁的使用方法,以及它们在保证线程安全上的效果。
170万+

被折叠的 条评论
为什么被折叠?



