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 }执行结果:
Lock、Synchronized锁区别解析文章插图
上面这个例子是模拟抢票功能 , 可以看到三个线程在拥有同一个类对象时会实现同步 , 那么如果把 “张三” 线程对象换成新 new 的对象 , 结果会怎样呢?
Lock、Synchronized锁区别解析文章插图
可以看到关于李四的票就会出现票数混乱 , 数据不能同步 。
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 }结果:
Lock、Synchronized锁区别解析文章插图
3、修饰代码块这个其实和前两种方式差不多 , 只不过它修饰的变成了某一段代码块 , 而前面两种修饰的是整个方法的代码块 , 并且修饰代码块可以自定义 “钥匙”, 这样使得实现更加灵活 , 所以一般是推荐使用 synchronized 修饰代码块实现线程同步的 。 同样还是以上面购票为例


推荐阅读