栗子来源:https://blog.csdn.net/wenzhi20102321/article/details/52524545
首先对java中同步锁与互斥锁进行区分,主要来源于知乎中的大佬总结如下:
1.锁的概念
锁的目的就是避免多个线程对同一个共享的数据并发修改带来的数据混乱。
锁的实现要处理的大概就只有这4个问题:(知乎大宽宽的回答,非本人观点)
- “谁拿到了锁“这个信息存哪里(可以是当前class,当前instance的markword,还可以是某个具体的Lock的实例)
-
谁能抢到锁的规则(只能一个人抢到 - Mutex;能抢有限多个数量 - Semaphore;自己可以反复抢 - 重入锁;读可以反复抢到但是写独占 - 读写锁……)
-
抢不到时怎么办(抢不到玩命抢;抢不到暂时睡着,等一段时间再试/等通知再试;或者二者的结合,先玩命抢几次,还没抢到就睡着)
-
如果锁被释放了还有其他等待锁的怎么办(不管,让等的线程通过超时机制自己抢;按照一定规则通知某一个等待的线程;通知所有线程唤醒他们,让他们一起抢……)
2.互斥与同步
互斥锁与同步锁的区别:(知乎:chen Kingwen的回答)
互斥是通过竞争对资源的独占使用,彼此之间不需要知道对方的存在,执行顺序是一个乱序。
同步是协调多个相互关联线程合作完成任务,彼此之间知道对方存在,执行顺序往往是有序的。
3.java中synchronized实现同步锁
synchronized为java中实现同步锁的关键字,可以以下几种对象、代码块、方法、类
- 代码块:被修饰的代码块为同步代码块,调用该代码块的对象是同步锁的操作对象
- 方法:被修饰的方法为同步方法,调用该方法的对象为同步锁的操作对象
- 静态方法:被static关键字修饰的方法属于类,那同步锁修饰的静态方法自然被操作对象为该类的所有实例对象
- 类:被修饰的类为同步类,该类的所有实例对象为同步锁的操作对象
4.实例(该实例来源于https://blog.csdn.net/wenzhi20102321/article/details/52524545)
使用同步锁及多线程实现模拟三台售票机售出同批次票:
/*
* 三个售票窗口同时售卖20张票
* 1.票数使用同一个静态值
* 2.保证不出现卖出同一个票数,java多线程同步锁
*/
public class Station extends Thread {
public Station(String name) {
super(name);//名字就以线程名进行命名
}
static int tick=20;//表示这个票数归类所有
static Object ob="aa";//静态钥匙,值是任意
public void run() {
while(tick>0) {
synchronized(ob) {//synchronized同步锁,以下钥匙aa为同步静态对象,这就解释了为什么定义为Object
if(tick>0) {
System.out.println(getName()+"卖出了第"+(21-tick)+"张票");
tick--;
}else {
System.out.println("票卖完了");
}
}
try {
sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
调用的主类:
public class Main_class {
/**
* java多线程同步锁的应用
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Station station1=new Station("窗口1");
Station station2=new Station("窗口2");
Station station3=new Station("窗口3");
station1.start();
station2.start();
station3.start();
}
}
演示结果: