传统的 synchronized
题目:三个售票员 卖出 30张票 : 1. 在高内聚低耦合的前提下, 线程 操作(对外暴露的调用方法) 资源类
传统的 synchronized
package juc;
public class SaleTicketDemo1 {
public static void main(String[] args) {
Ticket ticket=new Ticket();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}},"A").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}},"B").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}},"C").start();
}
}
class Ticket{
private int number=30;
//买票的方式
//synchronized 本质是队列 锁
public synchronized void sale(){
if(number>0){
System.out.println(Thread.currentThread().getName()+"卖出了第"+(number--)+"票,剩余"+number);
}
}
}
Lock锁
package juc;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SaleTicketDemo2 {
public static void main(String[] args) {
// 并发 。多线程操作同一个资源类,把资源类丢入线程
Ticket2 ticket =new Ticket2();
new Thread(()->{ for (int i = 0; i < 40; i++)ticket.sale(); },"A").start();
new Thread(()->{ for (int i = 0; i < 40; i++)ticket.sale(); },"B").start();
new Thread(()->{ for (int i = 0; i < 40; i++)ticket.sale(); },"C").start();
}
}
//lock 三部曲
//1 new ReentrantLock();
//2//加锁
// lock.lock();
//3 finally => lock.unlock();//解锁
class Ticket2{
private int number=30;
Lock lock =new ReentrantLock();
//买票的方式
public void sale(){
//加锁
lock.lock();
try {
//业务代码
if(number>0){
System.out.println(Thread.currentThread().getName()+"卖出了第"+(number--)+"票,剩余"+number);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();//解锁
}
}
}
结果:
synchronized 和 lock 区别
- 首先synchronized是java内置关键字,在jvm层面,Lock是个java类;
- synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
- synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;
- 用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;
- synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可)
- Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。