Lock、Synchronized锁区别解析
监视器(monitor)在了解这两种锁之前 , 先要知道一个概念 , "监视器" 。
监视器是操作系统实现同步的概念 , 一个监视器往往一个对象引用相关联 , 当一个监视器开始监视某一段代码时 , 其他的线程就需要拥有这个监视器对应的对象 , 监视器确认后才能让这个线程放行 , 继续执行后面的代码 。 可以说java 中的 synchronized、Lock 锁这些就是监视器 , 是 "监视器" 这个概念的实现 。
synchronizedsynchronized 是 java 的关键字 , 它可以修饰方法 , 代码块 , 下面先简单说一下它的用法 。
用法1、修饰实例方法 1public synchronized void test() { 2if(sum<0) { 3n=false; 4return ; 5} 6try { 7Thread.sleep(200); 8} catch (InterruptedException e) { 9// TODO 自动生成的 catch 块10e.printStackTrace();11}12System.out.println(Thread.currentThread().getName()+sum--);13}
这种方式锁住的是当前这个类的对象 , 如果两个线程创建了不同的对象 , 那么这个方法是锁不住的 , 只有这两个线程拥有同一个对象 , 然后拿这个对象作为钥匙抢夺CPU然后进入方法执行 。
1 public class safe1{ 2public static void main(String[] args) { 3QQ q=new QQ();4new Thread(q,"张三").start();// 如果这里的 q 换成了 new QQ() , 那么就不能实现同步作用了 5new Thread(q,"李四").start(); 6new Thread(q,"王五").start(); 78}9 10 }11 class QQ implements Runnable{12private int sum=100;13private boolean n=true;1415public synchronized void test() {16if(sum<0) {17n=false;18return ;19}20try {21Thread.sleep(200);22} catch (InterruptedException e) {23// TODO 自动生成的 catch 块24e.printStackTrace();25}26System.out.println(Thread.currentThread().getName()+sum--);27}28public void run() {29while(n) {30test();31}3233}34 35 }
执行结果:
文章插图
上面这个例子是模拟抢票功能 , 可以看到三个线程在拥有同一个类对象时会实现同步 , 那么如果把 “张三” 线程对象换成新 new 的对象 , 结果会怎样呢?
文章插图
可以看到关于李四的票就会出现票数混乱 , 数据不能同步 。
2、修饰类方法(静态方法)还是拿上面购票的例子来讲解 , 如果 synchronized 修饰静态方法 , 那么锁住的就是当前类 , 也就是 class 信息 , 因为 class 信息是在当前类加载时就被加载到方法区的 , 不同的对象都会拥有同一个该对象的类信息 , 所以在多线程下即使是不同对象 , 最后的结果也能实现同步
1 public class safe1{ 2public static void main(String[] args) { 3new Thread(new QQ(),"张三").start();4new Thread(new QQ(),"李四").start(); 5new Thread(new QQ(),"王五").start(); 67}89 }10 class QQ implements Runnable{11private static int sum=100;12private static boolean n=true;1314public synchronized static void test() {15if(sum<0) {16n=false;17return ;18}19try {20Thread.sleep(200);21} catch (InterruptedException e) {22// TODO 自动生成的 catch 块23e.printStackTrace();24}25System.out.println(Thread.currentThread().getName()+sum--);26}27public void run() {28while(n) {29test();30}3132}33 34 }
结果:
文章插图
3、修饰代码块这个其实和前两种方式差不多 , 只不过它修饰的变成了某一段代码块 , 而前面两种修饰的是整个方法的代码块 , 并且修饰代码块可以自定义 “钥匙”, 这样使得实现更加灵活 , 所以一般是推荐使用 synchronized 修饰代码块实现线程同步的 。 同样还是以上面购票为例
1 public class safe1{ 2public static void main(String[] args) { 3new Thread(new QQ(),"张三").start();4new Thread(new QQ(),"李四").start(); 5new Thread(new QQ(),"王五").start(); 67}89 }10 class QQ implements Runnable{11private static int sum=100;12private static boolean n=true;1314public void test() {15synchronized (QQ.class) {16if(sum<0) {17n=false;18return ;19}20try {21Thread.sleep(200);22} catch (InterruptedException e) {23// TODO 自动生成的 catch 块24e.printStackTrace();25}26System.out.println(Thread.currentThread().getName()+sum--);27}28}29public void run() {30while(n) {31test();32}3334}35 36 }
可以看到这次是在实例方法里 , 如果修饰在方法上锁住的就是当前类对象 , 不同线程必须拥有同一个对象才能实现同步 , 而在这个例子里 synchronized 锁住的是 .class 类信息 , 所以最后还是能实现同步
文章插图
原理因为 synchronized 是关键字 , 没有具体的类实现 , 所以我们只能在指令集上查看 , 先上代码
- 空调|让格力、海尔都担忧,中国取暖“新潮物”强势来袭,空调将成闲置品?
- 占营收|华为值多少钱
- 俄罗斯手机市场|被三星、小米击败,华为手机在俄罗斯排名跌至第三!
- 页面|如何简单、快速制作流程图?上班族的画图技巧get
- 操盘|中兴统一操盘中兴、努比亚、红魔三大品牌
- 印度|拒绝华为后,印度、英国斥资数十亿求助日本
- 华为|台积电、高通、华为、小米接连宣布!美科技界炸锅:怎么会这样!
- 拍照|iPhone12还没捂热13就曝光了,屏幕、信号、拍照均有升级!
- 路由器|家里无线网经常断网、网速慢怎么办?教你几个小窍门,轻松解决
- 一图看懂!数字日照、新型智慧城市这样建(上篇)|政策解读 | 新型