synchronized(作为关键字):
package com.han.demo01;
public class TestSaleTicket {
public static void main(String[] args) {
Ticket t = new Ticket();
new Thread(() -> {
for (int i = 0; i < 60; i++) {
t.sale();
}
}, "窗口1").start();
new Thread(() -> {
for (int i = 0; i < 60; i++) {
t.sale();
}
}, "窗口2").start();
new Thread(() -> {
for (int i = 0; i < 60; i++) {
t.sale();
}
}, "窗口3").start();
}
}
//OOP的思想
class Ticket {
private int num = 50;
public synchronized void sale() {
if (num > 0) {
System.out.println(Thread.currentThread().getName() + "卖出了NO." + (num--) + " 张票,还剩 " + num + " 张票。");
}
}
}
Lock(作为接口):
- 1.创建锁 Lock lock = new ReentrantLock();
- 2.加锁 lock.lock();
- 3.释放锁 lock.unlock();
可重入锁 ReentrantLock,无参构造默认为非公平锁。
public ReentrantLock() {
sync = new NonfairSync();
}
公平锁:多个线程按照申请锁的顺序去获得锁,线程会直接进入队列去排队,永远都是队列的第一位 才能得到锁。
优点:所有的线程都能得到资源,不会饿死在队列中。
缺点:吞吐量会下降很多,队列里面除了第一个线程,其他的线程都会阻塞,cpu唤醒阻塞线程的开销会很大。
非公平锁:多个线程去获取锁的时候,会直接去尝试获取,获取不到,再去进入等待队列,如果能获取到,就直接获取到锁。
优点:可以减少CPU唤醒线程的开销,整体的吞吐效率会高点,CPU也不必取唤醒所有线程,会减少唤起线程的数量。
缺点:你们可能也发现了,这样可能导致队列中间的线程一直获取不到锁或者长时间获取不到锁,导致饿死。
package com.han.demo01;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestLockSaleTicket {
public static void main(String[] args) {
TicketLock t = new TicketLock();
new Thread(() -> {
for (int i = 0; i < 60; i++) {
t.sale();
}
}, "窗口1").start();
new Thread(() -> {
for (int i = 0; i < 60; i++) {
t.sale();
}
}, "窗口2").start();
new Thread(() -> {
for (int i = 0; i < 60; i++) {
t.sale();
}
}, "窗口3").start();
}
}
class TicketLock {
private int num = 50;
private Lock lock = new ReentrantLock();
public void sale() {
try {
lock.lock();
if (num > 0) {
System.out.println(Thread.currentThread().getName() + "卖出了NO." + (num--) + " 张票,还剩 " + num + " 张票。");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//手动释放锁
lock.unlock();
}
}
}
Synchronized和Lock区别:
- Synchronized 内置的java关键字,Lock是一个java接口。
- Synchronized 无法判断获取锁的状态,Lock可以判断是否获取到了锁。
- Synchronized 会自动释放锁,Lock必须手动释放锁,如果不释放锁,会导致死锁。
- Synchronized 线程1(获得锁,阻塞)、线程2(等待,傻傻的等);Lock就不一定会等待下去。
- Synchronized,可重入锁,不可以中断,非公平;Lock,可重入锁,可以判断锁,非公平(自己可以设置)。
- Synchronized 使用锁少量的代码同步问题,Lock适合锁大量的同步代码。