• Java内置锁和简单用法


    一、简单的锁知识

    关于内置锁

    Java具有通过synchronized关键字实现的内置锁,内置锁获得锁和释放锁是隐式的,进入synchronized修饰的代码就获得锁,走出相应的代码就释放锁。

    java内置锁是一个互斥锁,这就是意味着最多只有一个线程能够获得该锁,当线程A尝试去获得线程B持有的内置锁时,线程A必须等待或者阻塞,直到线程B释放这个锁,如果B线程不释放这个锁,那么A线程将永远等待下去。

    对象锁和类锁

    这其实也是Java的内置锁。

    对象锁是用于对象实例方法,或者一个对象实例上的,类锁是用于类的静态方法或者一个类的class对象上的。我们知道,类的对象实例可以有很多个,但是每个类只有一个class对象,所以不同对象实例的对象锁是互不干扰的,但是每个类只有一个类锁。但是有一点必须注意的是,其实类锁只是一个概念上的东西,并不是真实存在的,它只是用来帮助我们理解锁定实例方法和静态方法的区别的。

    二、synchronized所代表的内置锁的使用方法

    1.synchronized修饰普通方法

    class A {
      public
    synchronized void test() {   }
      public void test2() {

      }
    }

    这种情况下,用的其实是这个方法所在的类的实例对象的锁,也就是A的一个实例的对象锁。意思是,比如A a = new A();,如果两个线程同时调用了a的这个test方法,那么先调用的那个线程,就先拿到这个实例a的对象锁,而另一个线程呢,就要只能等拿到a锁的那个线程运行完这个test方法后,把锁放了,然后再抢到实例a对象锁后才能运行这个test方法。

    注意,虽然说锁的是这个方法所在类的实例对象,但其他线程是可以自由访问这个对象中的非同步方法的。比如这个A类中还有另一个方法叫test2,是不同步的,那么即使线程1抢到对象锁,在进行test方法中,线程2是可以同时访问运行test2方法的,因为这是个不同步的方法。

    2.同步块(对象锁)

    class A {
        public void test() {
            synchronized(this) {//也可以锁其他对象
                xxx
            }
        }
    }

    这个锁的也是某个对象的实例。

    3.类锁(同步块)

    class A {
        public void test() {
            synchronized(A.class) {
                xxx
            }
        }
    }

    其实一鬼样的,就是之前锁的是实例对象,现在锁的是一个类,或者说是一个类对象(Class Object),类锁只是抽象出来的一个概念,而且因为类的Class Object或者说加载的类信息只有一个,所有抽象出来个类锁。

    4.类锁之——修饰static方法

    class A {
        public static synchronized void test() {
            
        }
    }

    synchronized修饰static的方法的时候,也是类锁,锁的也是这个类,或者说是这个类的Class Object,因为静态方法是所有对象实例共有的,一个类只有一个,static方法也是在类加载的时候就加载了,所以synchronized修饰static方法的时候,锁也是唯一的,所以也是类锁哦。

    三、关于类锁和对象锁的注意:

    看下这个例子:

    public class TestSynchronized 
    {  
        public synchronized void test1() 
        {  
                  int i = 5;  
                  while( i-- > 0) 
                  {  
                       System.out.println(Thread.currentThread().getName() + " : " + i);  
                       try 
                       {  
                            Thread.sleep(500);  
                       } 
                       catch (InterruptedException ie) 
                       {  
                       }  
                  }  
        }  
        public static synchronized void test2() 
        {  
             int i = 5;  
             while( i-- > 0) 
             {  
                  System.out.println(Thread.currentThread().getName() + " : " + i);  
                  try 
                  {  
                       Thread.sleep(500);  
                  } 
                  catch (InterruptedException ie) 
                  {  
                  }  
             }  
        }  
        public static void main(String[] args) 
        {  
             final TestSynchronized myt2 = new TestSynchronized();  
             Thread test1 = new Thread(  new Runnable() {  public void run() {  myt2.test1();  }  }, "test1"  );  
             Thread test2 = new Thread(  new Runnable() {  public void run() { TestSynchronized.test2();   }  }, "test2"  );  
             test1.start();  
             test2.start();  
    //         TestRunnable tr=new TestRunnable();
    //         Thread test3=new Thread(tr);
    //         test3.start();
        } 
    }
     
    
    test1 : 4
    test2 : 4
    test1 : 3
    test2 : 3
    test2 : 2
    test1 : 2
    test2 : 1
    test1 : 1
    test1 : 0
    test2 : 0

    上面代码synchronized同时修饰静态方法和实例方法,但是运行结果是交替进行的,这证明了类锁和对象锁是两个不一样的锁,控制着不同的区域,它们是互不干扰的。同样,线程获得对象锁的同时,也可以获得该类锁,即同时获得两个锁,这是允许的。

    其实这个也很显然,一个锁的是类的实例,一个是类的Class Object,这两个都不是一个东西hh。

    四、synchronized中条件判断用while而不是用if

    例子见这篇文章:https://www.cnblogs.com/heyboom/p/9147469.html

  • 相关阅读:
    Python学习之路:MINST实战第一版
    Python学习之路:NumPy进阶
    Python学习之路:NumPy初识
    Python学习之路:一天搞定基础部分
    7. 整数反转(leetcode)
    1. 两数之和(leetcode)
    172. 阶乘后的零(leetcode)
    Java模拟斗地主发牌(Collections工具类的应用)
    CF刷题-Codeforces Round #481-G. Petya's Exams
    【android】安卓平台版本和API版本的对应关系
  • 原文地址:https://www.cnblogs.com/wangshen31/p/10432363.html
Copyright © 2020-2023  润新知