多线程中常用的两种确保线程安全的方式
①、synchronized的方式(用于代码块或者方法上面)
②、Lock锁的方式
下面以卖票为案例
一、卖票的案例代码?
//利用synchronized修饰方法达到线程安全
public class SaleTicketSynchronizedMethod {
public static void main(String[] args) {
Ticket1 ticket1 = new Ticket1(40);
new Thread(()->{ for(int i=0;i<20;i++) ticket1.saleTicket(); },"A").start();
new Thread(()->{ for(int i=0;i<20;i++) ticket1.saleTicket(); },"B").start();
new Thread(()->{ for(int i=0;i<20;i++) ticket1.saleTicket(); },"C").start();
new Thread(()->{ for(int i=0;i<20;i++) ticket1.saleTicket(); },"D").start();
}
}
class Ticket1{
private Integer count;
public Ticket1(Integer count){this.count = count;}
public synchronized void saleTicket(){
if(this.count>0){
System.out.println("当前的线程"+Thread.currentThread().getName()+"正在卖票,卖出了"+(count--)+",剩余"+count);
}
}
}
//利用lock锁的方法
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//利用Lock锁
public class SaleTicketLockMethod {
public static void main(String[] args) {
Ticket2 ticket2 = new Ticket2(40);
new Thread(()->{ for(int i=0;i<20;i++) ticket2.saleTicket(); },"A").start();
new Thread(()->{ for(int i=0;i<20;i++) ticket2.saleTicket(); },"B").start();
new Thread(()->{ for(int i=0;i<20;i++) ticket2.saleTicket(); },"C").start();
new Thread(()->{ for(int i=0;i<20;i++) ticket2.saleTicket(); },"D").start();
}
}
class Ticket2{
private Integer count;
Lock lock = new ReentrantLock();
public Ticket2(Integer count){this.count = count;}
public void saleTicket(){
lock.lock();
try {
//放业务代码
if(this.count>0){
System.out.println("当前的线程"+Thread.currentThread().getName()+"正在卖票,卖出了"+(count--)+",剩余"+count);
}
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
二、synchronized和Lock的区别
①、Synchronized是一个关键字,Lock是一个Java类
②、Synchronized是无法判断获取锁的状态,Lock可以判断是否获得锁
③、Synchronized自动释放锁,Lock需要手动释放
④、Synchronized的锁如果一个线程获取锁阻塞了,那其他的会一直等,Lock不会
⑤、Synchronized是可重入锁,非公平,不可中断。Lock可中断,公平性可自己设置
⑥、Synchronized适合锁少量的代码同步问题,Lock适合大量的代码(灵活性高)
⑦、Synchronized只有两种用法(代码块、修饰方法)