2010-09-15 150 views

回答

38

不,这并不意味着。 “级别锁定”只是对不同对象的常规锁定,即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

如果两个方法都声明为静态,该怎么办?我相信在这种情况下,两者将会相互排斥,这是否正确? – buch11 2015-10-07 05:19:51

+2

@ buch11:这是正确的,就好像两个人都在执行'synchronized(SomeClass.class){...}',并且禁止任何复杂的类加载场景,在两种情况下这都是相同的对象。从技术上讲,类加载允许你对同一个类有两个单独的“加载”,并且你可以在这些不同的类中同时运行静态同步方法。但除了这种怯懦,它是互相排斥的。 – 2015-10-07 18:38:53

+0

您可能想知道在调用静态同步方法时会发生什么,因为静态方法与类关联,而不是对象。在这种情况下,线程获取与该类关联的Class对象的内部锁。 **因此,对类的静态字段的访问由与该类的任何实例的锁不同的锁控制。** [Source](https://docs.oracle.com/javase/tutorial/essential/concurrency /locksync.html) – Eduardo 2017-03-28 05:17:25

6

在java中有两种类型的锁:

  1. 职业等级
  2. 对象级别

在静态方法情况下,锁总是在 类,但在实例的情况下检查方法总是在对象上检查锁。

实施例:

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   
12

对象级锁:

对象级锁定机制时,要同步非静态方法和非静态代码块,使得只有一个线程将能够在类的给定实例上执行代码块。这应该始终做到使实例级数据线程安全。这可以如下完成:

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

实施例理解对象和类级锁在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 

同步块被去为相同的线程中执行。

0

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

Courtesy

1

类水平锁定由关键字“静态同步,其中,作为对象电平由同步关键词只实现来实现。 对象级锁定实现,以限制同一对象通过不同的线程,其中操作因为实现了级别锁定以限制任何对象操作。

0

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

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

}

2)

公共类DemoClass {

public void demoMethod(){ 

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

}

3)

公共类DemoClass {

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

    synchronized(lock){ 
     //dosomething 
    } 
} 

}

+0

这是如何回答这个问题的? – shmosel 2017-04-20 04:45:26

0

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

但是,如果一个线程获得了Class级别的锁定,那么另一个线程可以获得其实例上的一个锁定。两者都可以工作parallel.`

package lock; 

class LockA implements Runnable { 
    @Override 
    public void run() { 
     synchronized (LockA.class) { 
      System.out.println("Class"); 
      try { 
       Thread.sleep(60 * 1000); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 
public class TestClassVsInstanceLock { 
    public static void main(String[] args) { 
     final LockA a = new LockA(); 
     final LockA b = new LockA(); 
     try { 
      Thread t = new Thread(a); 
      Thread t1 = new Thread() { 
       @Override 
       public void run() { 
        synchronized (b) { 
         System.out.println("Instance 1"+ currentThread().currentThread().holdsLock(b)); 
         try { 
          Thread.sleep(10 * 1000); 
         } catch (InterruptedException e) { 
          e.printStackTrace(); 
         } 
        } 
       } 
      }; 
      t.start(); 
      t1.start(); 
      synchronized (a) { 
       System.out.println("Instance2"); 
       Thread.sleep(10 * 1000); 
      } 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

`

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

一切都将立刻被印刷没有任何停顿。

2

如果线程T1进入通过获取类级锁定的方法M1,这意味着另一线程T2不能运行通过获取对象级锁不同的方法平方米?

对象级锁和类级锁是不同的。在上述情况下,T2可以通过获取对象级别锁定来运行方法m2。但是,如果m2为static synchronized,则除非方法m1上的T1释放类级锁定,否则T2不能调用m2方法。

Object level lock

这是不可能的的同一对象上​​方法两个调用交织。当一个线程正在执行一个对象的​​方法时,所有其他线程将调用​​方法用于同一对象块(挂起执行),直到第一个线程完成对象。

假设你有对象O. 2点​​方法M1和M2如果线程T1是在方法M1的执行中,那么线程T2必须等待呼吁同一个对象O,除非线程T1释放锁法平方米在方法m1上。

Class level lock

线程获取了与类相关的Class对象的内部锁。因此,访问类的static字段由与该类的任何实例的锁截然不同的锁控制。

假设方法m1是static synchrnozed而方法m2也是static synchronized并且您有两个不同的对象o1和o2。

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