一. 修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁。
二. 修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁。
三. 修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象。
synchronized同步块使用了monitorenter和monitorexit指令实现同步,这两个指令,本质上都是对一个对象的监视器(monitor)进行获取,这个过程是排他的,也就是说同一时刻只能有一个线程获取到由synchronized所保护对象的监视器。
线程执行到monitorenter指令时,会尝试获取对象所对应的monitor所有权,也就是尝试获取对象的锁,而执行monitorexit,就是释放monitor的所有权。
第一步:创建一个资源类
第二步:创建多个线程,调用资源类的方法
例如:
public class SaleTicket {public static void main(String[] args) {//第二步:创建多个线程,调用资源类的方法Ticket ticket = new Ticket();new Thread(new Runnable() {@Overridepublic void run() {for(int i=0;i<40;i++){ticket.sale();}}},"ThreadA").start();new Thread(new Runnable() {@Overridepublic void run() {for(int i=0;i<40;i++){ticket.sale();}}},"ThreadB").start();new Thread(new Runnable() {@Overridepublic void run() {for(int i=0;i<40;i++){ticket.sale();}}},"ThreadC").start();}
}
//第一步:创建一个资源类
class Ticket{private int number=30;public synchronized void sale(){if(number>0){System.out.println(Thread.currentThread().getName()+":卖出第"+number--+"张票,剩下"+number+"张票");}}
}
运行结果:
Lock锁实现提供了比使用同步方法和语句可以获得的更广泛的锁操作。它们允许更灵活的结构,可能具有非常不同的属性,并且可能支持多个关联的条件对
象。Lock提供了比synchronized更多的功能。
import java.util.concurrent.locks.ReentrantLock;//创建多个线程调用资源类的方法
public class LockSaleTicket {public static void main(String[] args) {LTicket lTicket = new LTicket();new Thread(()->{lTicket.sale();},"线程A").start();new Thread(()->{for (int i = 0; i <30 ; i++) {lTicket.sale();}},"线程B").start();new Thread(()->{lTicket.sale();},"线程C").start();}
}
//第一步:创建一个资源类
class LTicket{int number=30;private final ReentrantLock lock =new ReentrantLock();public void sale(){//上锁lock.lock();try{//判断是否有票if(number>0){System.out.println(Thread.currentThread().getName()+":卖出第"+number--+"张票,剩下"+number+"张票");}}finally {//解锁lock.unlock();}}
}