Java类级别锁定与对象级别锁定

时间:2010-09-15 13:38:03

标签: java multithreading locking

如果线程T1通过获取类级别锁定进入方法m1,这是否意味着另一个线程T2无法通过获取对象级别锁定来运行不同的方法m2?

11 个答案:

答案 0 :(得分:46)

不,这并不意味着。 “类级别锁定”只是对不同对象的常规锁定,即SomeClass.class。 “对象级别锁定”锁定在this上。

编辑:为了确保我遵循您对术语的理解,您想知道m1和m2是否可以同时运行,如下所示:

public class SomeClass {
    public synchronized static void m1() {
       //do something
    }

    public synchronized void m2() {
       //do something
    }
}

答案是肯定的,m1和m2可以同时运行。它在功能上等同于:

public class SomeClass {
    public static void m1() {
        synchronized (SomeClass.class) {
           //do something
        }
    }
    public void m2() {
        synchronized (this) {
           //do something
        }
    }
}

由于它们在完全不同的对象上进行同步,因此它们不是互斥的。

答案 1 :(得分:17)

对象级锁定:

当您想要同步非静态方法或非静态代码块时,对象级锁定是一种机制,这样只有一个线程能够在给定的类实例上执行代码块。应始终这样做以使实例级数据线程安全。这可以通过以下方式完成:

public class DemoClass 
{ 
  public synchronized void demoMethod(){} 
} 

or 

public class DemoClass 
{ 
  public void demoMethod(){ 
  synchronized (this) 
  { 
   //other thread safe code 
  } 
 } 
} 

or 

public class DemoClass 
{ 
  private final Object lock = new Object(); 
  public void demoMethod(){ 
  synchronized (lock) 
 { 
  //other thread safe code 
 } 
} 

类级别锁定:

类级别锁定可防止多个线程在运行时的所有可用实例中的同步块中输入。这意味着如果在运行时有100个DemoClass实例,那么一次只有一个线程可以在任何一个实例中执行demoMethod(),并且其他所有实例都将被锁定用于其他线程。应始终这样做以使静态数据线程安全。

public class DemoClass 
{ 
  public synchronized static void demoMethod(){} 
} 

or 

public class DemoClass 
{ 
  public void demoMethod(){ 
  synchronized (DemoClass.class) 
  { 
   //other thread safe code 
  } 
 } 
} 

or 

public class DemoClass 
{ 
 private final static Object lock = new Object(); 
 public void demoMethod(){ 
 synchronized (lock) 
  { 
   //other thread safe code 
  } 
 } 
}

答案 2 :(得分:6)

在java中有两种类型的锁:

  1. 班级
  2. 对象级别
  3. 如果是静态方法,则始终在课堂上检查锁定      但是在实例方法的情况下,总是在对象上检查锁。

    示例:

    show1() 非静态show() 静态。 现在,show()由类名(或对象)和 对象调用show1(),然后可以访问这两个方法 同时由两个线程组成。

    class Shared{
        static int x;
        static synchronized void show(String s,int a){
            x=a;
            System.out.println("Starting in method "+s+" "+x);
            try{
                Thread.sleep(2000);
            }
            catch(Exception e){ }
            System.out.println("Ending from method "+s+" "+x);
        }
        synchronized void show1(String s,int a){
            x=a;
            System.out.println("Starting show1 "+s);
            try{
                Thread.sleep(2000);
            }
            catch(Exception e){ }
            System.out.println("Ending from show1 "+s);
        }
    }
    class CustomThread extends Thread{
        Shared s;
        public CustomThread(Shared s,String str){
            super(str);
            this.s=s;
            start();
        }
        public void run(){
            Shared.show(Thread.currentThread().getName(),10);
        }
    }
    class CustomThread1 extends Thread{
        Shared s;
        public CustomThread1(Shared s,String str){
            super(str);
            this.s=s;
            start();
        }
        public void run(){
            s.show1(Thread.currentThread().getName(),20);
        }
    }
    public class RunSync {
        public static void main(String[] args) {
            Shared sh=new Shared();
            CustomThread t1=new CustomThread(sh,"one");
            CustomThread1 t2=new CustomThread1(sh,"two");
        }
    }
    

    输出:

    Starting in method one 10
    Starting show1 two
    Ending from method one 20
    Ending from show1 two        
    

答案 3 :(得分:5)

  

了解Java中的对象和类级锁的示例

1)对象级锁定示例

package com.test;

public class Foo implements Runnable {

    @Override
    public void run() {
        Lock();
    }
    public void Lock() {
        System.out.println(Thread.currentThread().getName());
        synchronized(this) {
            System.out.println("in block " + Thread.currentThread().getName());
            System.out.println("in block " + Thread.currentThread().getName() + " end");
        }
    }

    public static void main(String[] args) {
        Foo b1 = new Foo();
        Thread t1 = new Thread(b1);
        Thread t2 = new Thread(b1);             
        Foo b2 = new Foo();
        Thread t3 = new Thread(b2);             
        t1.setName("t1");
        t2.setName("t2");
        t3.setName("t3");             
        t1.start();
        t2.start();
        t3.start();
    }
}
  

输出:

    t1
    t3
    t2
    in block t3
    in block t1
    in block t3 end
    in block t1 end
    in block t2

注意,当线程t1和t2阻塞时,t3不会阻塞。因为锁定放在这个对象上,并且线程 t3具有与线程t1不同的此对象,t2

2)班级锁定示例

对象级锁定中的代码,只在同步块中添加了Foo.class。 使用Foo类对象创建的所有线程都将被阻止。

package com.test;    
public class Foo implements Runnable {        
    @Override
    public void run() {
        Lock();
    }

    public void Lock() {
        System.out.println(Thread.currentThread().getName());
        synchronized(Foo.class) {
            System.out.println("in block " + Thread.currentThread().getName());
            System.out.println("in block " + Thread.currentThread().getName() + " end");
        }
    }

    public static void main(String[] args) {
        Foo b1 = new Foo();
        Thread t1 = new Thread(b1);
        Thread t2 = new Thread(b1);             
        Foo b2 = new Foo();
        Thread t3 = new Thread(b2);             
        t1.setName("t1");
        t2.setName("t2");
        t3.setName("t3");             
        t1.start();
        t2.start();
        t3.start();
    }
}
  

输出:

t1
t3
in block t1
in block t1 end
t2
in block t3
in block t3 end
in block t2
in block t2 end

将为同一个线程执行同步块。

答案 4 :(得分:2)

类级别锁定是通过关键字" Static Synchronized实现的,其中对象级别仅通过synchronized关键字实现。 实现对象级锁定以限制同一对象通过不同的线程进行操作,同时实现类级别锁定以限制任何对象操作。

答案 5 :(得分:2)

  

如果线程T1通过获取类级别锁定进入方法m1,这是否意味着另一个线程T2无法通过获取对象级别锁定来运行不同的方法m2?

对象级别锁定和类级别锁定是不同的。在上述情况下,T2可以通过获得对象级别锁定来运行方法m2。但是如果m2是"C1","C2","C3","C4","C5","C6" a,b,c,d,e,f a,"b1,b2,b3",c,d,"e1,e2,e3,e4",f ,则T2不能调用m2方法,除非T1释放类级锁定方法m1。

Object level lock

同一对象上的两个Option Explicit Dim goFS : Set goFS = CreateObject("Scripting.FileSystemObject") Dim sDDir : sDDir = goFS.GetParentFolderName(WScript.ScriptFullName) Dim oCN : Set oCN = CreateObject("ADODB.Connection") Dim sCS : sCS = Join(Array( _ "Driver=Microsoft Access Text Driver (*.txt, *.csv)" _ , "DBQ=" & sDDir _ , "Extensions=asc,csv,tab,txt" _ ), ";") Dim oRS WScript.Echo "sCS:", sCS oCN.Open sCS Set oRS = oCN.Execute("SELECT * FROM [44187292.csv]") WScript.Echo oRS.GetString(2, , vbCrLf, vbCrLf & "----------" & vbCrLf, "<null>") oCN.close 方法调用不可能交错。当一个线程正在为一个对象执行cscript 44187292.vbs sCS: Driver=Microsoft Access Text Driver (*.txt, *.csv);DBQ=e:\work\proj\soa\tmp;Extensions=asc,csv,tab,txt a b c d e f ---------- a b1,b2,b3 c d e1,e2,e3,e4 f ---------- 方法时,所有其他线程都会为同一个对象阻塞static synchronized方法(暂停执行),直到第一个线程完成该对象为止。

假设在对象O上有两个synchronized方法m1和m2。 如果线程T1处于执行方法m1的中间,则线程T2必须等待在相同的对象O上调用方法m2,除非线程T1释放对方法m1的锁定。

Class level lock

Thread获取与该类关联的synchronized对象的内部锁。因此,对类的synchronized字段的访问由与该类的任何实例的锁不同的锁控制。

假设方法m1为synchronized且方法m2也为Class,并且您有两个不同的对象o1和o2。

如果线程T1在对象o1上执行方法m1的中间,则线程T2必须等待在对象o2上调用方法m2,除非线程T1在方法m1上释放锁定。

答案 6 :(得分:1)

类级别锁定的不同方式: 1) 公共类DemoClass {

public static synchronized void demoMethod(){
    //dosomething
}

}

2)

public class DemoClass {

public void demoMethod(){

    synchronized(DemoClass.class){
        //dosomething
    } 
}

}

3)

public class DemoClass {

private final static Object lock = new Object(); 
public void demoMethod(){

    synchronized(lock){
        //dosomething
    } 
}

}

答案 7 :(得分:0)

  

静态同步和非静态同步方法可能同时或同时运行,因为它们锁定在不同的对象上。

Courtesy

答案 8 :(得分:0)

类级别锁定和实例级别锁定都不同。两者都不会互相干扰锁定状态。如果一个类的一个实例已经被一个线程锁定,那么另一个线程无法获得该实例的锁定,除非第一个线程释放锁定。 类级别锁定的行为相同。

但是如果一个线程获得了Class级别的锁,那么另一个线程可以获取其某个实例的锁。两者都可以并行工作。

from pydub import AudioSegment
sound = AudioSegment.from_mp3("i.mp3")
sound.export("F:\\bh", format="wav")

`

这将打印: - 实例2 类 实例1true

所有内容都会立即打印出来。

答案 9 :(得分:0)

不,两者都可以同时执行。 1.如果将类级别锁应用于一个方法 synchronized(SomeClass.class),而将另一种方法将对象级别锁应用于 synchronized(this),则两者都可以在同时。

仅当在两个方法上都应用了类级别锁时,才可以并行执行。

原因是:对于类,jvm为java.lang.Class创建对象,即Java中的所有对象都是对象。因此,当对两个方法应用类级别锁时,对类对象应用通用锁,并且每个对象都具有单个锁,因此,每个线程都在等待,但是当使用不同的实例调用第二个方法并且在该实例上应用实例级别锁时时间,此对象锁的应用不同于类对象锁,因此可以并发执行。

答案 10 :(得分:0)

实例级别锁定,使用实例级别锁定一次只能执行一个线程。

 public class Refactor implements Runnable {
        private Object obj;

        public Refactor(Object obj)
        {
            this.obj = obj;
        }

        public void run() {

            if (Thread.currentThread().getName().equalsIgnoreCase("Test1")) {
                test1();
            } else {
                test2();
            }

        }

        public void test1() {
            synchronized (obj) {
                System.out.println("Test1");
            }
        }

        public synchronized void test2() {
            synchronized (obj) {
                System.out.println("Test2");
            }
        }

        public static void main(String[] args) {
            Object obj = new Object();
            Thread t1 = new Thread(new Refactor(obj));
            t1.setName("Test1");
            t1.start();
            Thread t2 = new Thread(new Refactor(obj));
            t2.setName("Test2");
            t2.start();
        }

    }

类级别锁定,使用类级别锁定一次只能执行一个线程。

public class Refactor implements Runnable {
    private Object obj;

    public Refactor(Object obj)
    {
        this.obj = obj;
    }

    public void run() {

        if (Thread.currentThread().getName().equalsIgnoreCase("Test1")) {
            test1();
        } else {
            test2();
        }

    }

    public static void test1() {
        synchronized (Refactor.class) {
            System.out.println("Test1");
        }
    }

    public static synchronized void test2() {
        synchronized (Refactor.class) {
            System.out.println("Test2");
        }
    }

    public static void main(String[] args) {
        Object obj = new Object();
        Thread t1 = new Thread(new Refactor(obj));
        t1.setName("Test1");
        t1.start();
        Thread t2 = new Thread(new Refactor(obj));
        t2.setName("Test2");
        t2.start();
    }

}