zoukankan      html  css  js  c++  java
  • 深入理解Java中Synchronized(对象锁)和Static Synchronized(类锁)的区别

    一、知识点回顾:
       1.、synchronized是Java中的关键字,是一种同步锁
       2、synchronized关键字可以用在方法和代码块上。这些方法或者代码块可以使静态的也可以是非静态的。
       3、在java中同步由synchronized关键字实现的,你可以在你类中的方法或者块上使用synchronized关键字,关键字不能在类定义的变量或者属性上使用。
    对象级别的锁
    public class DemoClass {
    public synchronized void demoMethod(){}
    }
    public class DemoClass {
    public void demoMethod(){
    synchronized (this) {
    //other thread safe code
    }
    }
    }
    public class DemoClass {
    private final Object lock = new Object();
    public void demoMethod(){
    synchronized (lock){
    //other thread safe code
    }
    }
    }
    类级别的锁
    public class DemoClass {
    public synchronized static void demoMethod(){}
    }
    public class DemoClass{
    public void demoMethod(){
    synchronized (DemoClass.class){
    //other thread safe code
    }
    }
    }
    public class DemoClass {
    private final static Object lock = new Object();
    public void demoMethod(){
    synchronized (lock){
    //other thread safe code
    }
    }
    }
    二、一段代码枷锁后的执行步骤
       ①一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,
       ②在Java里边就是拿到某个同步对象的锁(一个对象只有一把锁);
       ③如果这个时候同步对象的锁被其他线程拿走了,他(这个线程)就只能等了(线程阻塞在锁池等待队列中)。 
       ④取到锁后,他就开始执行同步代码(被synchronized修饰的代码); 
       ⑤线程执行完同步代码后马上就把锁还给同步对象,其他在锁池中等待的某个线程就可以拿到锁执行同步代码了。
       ⑥这样就保证了同步代码在统一时刻只有一个线程在执行。     

    三、Synchronized和Static Synchronized区别
           synchronized是对类的当前实例(当前对象)进行加锁,防止其他线程同时访问该类的该实例的所有synchronized块,注意这里是“类的当前实例”, 类的两个不同实例就没有这种约束了。
          static synchronized恰好就是要控制类的所有实例的并发访问,static synchronized是限制多线程中该类的所有实例同时访问jvm中该类所对应的代码块
          实际上,在类中如果某方法或某代码块中有 synchronized,那么在生成一个该类实例后,该实例也就有一个监视块,防止线程并发访问该实例的synchronized保护块,而static synchronized则是所有该类的所有实例公用得一个监视块
    写个demo验证下
    public class MyThread extends Thread {
    private static volatile int n = 0;

    public void run() {
    for (int i = 0; i < 10; i++) {
    add();
    try {
    sleep(5);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }


    private static synchronized void add() {
    n++;
    }

    public static void main(String[] args) throws InterruptedException {
    Thread threads[] = new Thread[100];
    for (int i = 0; i < threads.length; i++) {
    threads[i] = new MyThread();
    }
    for (Thread thread : threads) {
    thread.start();
    }
    for (Thread thread : threads) {
    thread.join(); //等待该线程终止
    }
    System.out.println(" n= " + n);
    }
    }
    运行结果   n= 1000
    然后我们把add()方法前的static去掉试下,结果是994,运行结果是不确定的,但都小于1000

    四、总结
         1、 除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。用法是: synchronized(this){/*区块*/}(或者synchronized(obj){/*区块*/}),它的作用域是当前对象; 被synchronized修饰符修饰的实例方法,跟整个方法体被一个synchronized(this) { ... } 包围住,虽然字节码看起来有差异,但语义完全一样。
          2、synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法;
         3、根据java语言的规定,你不能在构造方法上使用synchronized关键字,这是非法的并且会导致编译错误
         4、java中的同步方法会增加你程序的性能的消耗,所以只有在正真需要的时候才使用同步。同样,使用同步代码块的地方是你代码中关键的地方。

  • 相关阅读:
    Spring 缓存抽象
    Nginx配置入门
    CSS 小结笔记之解决flex布局边框对不齐
    CSS 小结笔记之图标字体(IconFont)
    CSS 小结笔记之em
    CSS 小结笔记之BFC
    CSS 实例之滚动的图片栏
    CSS 实例之翻转图片
    CSS 实例之打开大门
    CSS 小结笔记之伸缩布局 (flex)
  • 原文地址:https://www.cnblogs.com/ZenoLiang/p/14713160.html
Copyright © 2011-2022 走看看