public class SaleTicketDemo {
public static void main(String[] args) {
Ticket ticket = new Ticket();
new Thread(() -> {
for (int i = 0;i<50;i++){
ticket.sale();
}
},"A").start();
new Thread(() -> {
for (int i = 0;i<50;i++){
ticket.sale();
}
},"B").start();
new Thread(() -> {
for (int i = 0;i<50;i++){
ticket.sale();
}
},"C").start();
}
}
class Ticket{
private Integer number = 50;
public void sale() {
try {
Thread.sleep(500); //沉睡0.5秒,代替业务执行时间,否则执行业务太短会出现一个线程卖出所有票的情况
} catch (InterruptedException e) {
e.printStackTrace();
}
if (number > 0){
number--;
System.out.println(Thread.currentThread().getName()+"卖出一张票,剩余"+number+"张");
}
}
}
由运行结果可以看出多线程不对资源进行加锁控制会造成,重复扣减问题。
class Ticket{
private Integer number = 30;
public synchronized void sale() {
try {
Thread.sleep(500); //沉睡0.5秒,代替业务执行时间,否则执行业务太短会出现一个线程卖出所有票
} catch (InterruptedException e) {
e.printStackTrace();
}
if (number > 0){
number--;
System.out.println(Thread.currentThread().getName()+"卖出一张票,剩余"+number+"张");
}
}
}
在资源类Ticket的sale方法使用synchronized关键字就可以达到下面想要的效果
除了synchronized,还可以使用juc 下的Lock接口达到以上效果
、
使用方式 Lock lock = new ReentrantLock(); lock.lock(); try{ //业务代码块 }catch(){}finally{ lock.unlock()}
class Ticket{
private Integer number = 30;
Lock lock = new ReentrantLock(); //公平锁
public void sale() {
lock.lock();
try {
Thread.sleep(500); //沉睡0.5秒,代替业务执行时间,否则执行业务太短会出现一个线程卖出所有票
if (number > 0){
number--;
System.out.println(Thread.currentThread().getName()+"卖出一张票,剩余"+number+"张");
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
Lock 和synchronized的区别:
1、synchronized 是java的内置关键字,Lock 是一个java类
2、synchronized会自动释放锁,Lock必须手动释放锁,如果不释放会造成死锁
3、synchronized是阻塞式的(线程A获得锁,阻塞,线程B需要等A释放才能获得锁),Lock锁就不一定会等待下去(可以使用lock.tryLock方法尝试获取锁)
4、synchronized 是可重入锁,不可以中断,非公平;Lock ,也是可重入锁,可以判断锁,非公平锁(创建时指定参数可以设置为公平锁)
5、synchronized 适合少量代码块的同步问题,Lock适合同步大量的代码块。