任何一个可以告诉我的优势的同步方法同步框有一个例子吗?

有帮助吗?

解决方案

  

谁能告诉我同步方法的优势用一个例子同步块?感谢。

有是不使用同步方法超过块的一个明显的优势。

也许只有一个(但我不会把它的优势)是你不需要包含对象引用this

方法:

public synchronized void method() { // blocks "this" from here.... 
    ...
    ...
    ...
} // to here

块:

public void method() { 
    synchronized( this ) { // blocks "this" from here .... 
        ....
        ....
        ....
    }  // to here...
}

请参阅?没有任何优势可言。

块的具有优于方法的优点,虽然,大多在灵活性,因为可以使用另一个对象作为锁定而同步的方法将锁定整个对象。

比较

// locks the whole object
... 
private synchronized void someInputRelatedWork() {
    ... 
}
private synchronized void someOutputRelatedWork() {
    ... 
}

VS。

// Using specific locks
Object inputLock = new Object();
Object outputLock = new Object();

private void someInputRelatedWork() {
    synchronized(inputLock) { 
        ... 
    } 
}
private void someOutputRelatedWork() {
    synchronized(outputLock) { 
        ... 
    }
}

此外,如果该方法的增长仍然可以保持分离的同步部分:

 private void method() {
     ... code here
     ... code here
     ... code here
    synchronized( lock ) { 
        ... very few lines of code here
    }
     ... code here
     ... code here
     ... code here
     ... code here
}

其他提示

唯一的区别在于,同步块可以选择它同步于哪个对象。一个同步方法只可以使用'this'(或相应的类实例为同步类方法)。例如,这些在语义上等价的:

synchronized void foo() {
  ...
}

void foo() {
    synchronized (this) {
      ...
    }
}

后者是更灵活的,因为它可以为任何对象,通常是一个成员变量的相关的锁竞争。它也更精细,因为你可以有方法中执行前和后挡,但仍并发代码。当然,你可以很容易地通过重构并发代码放到单独的非同步方法使用synchronized方法。可使用任何使代码能更明显易懂。

同步法

优点:

  • 您的 IDE 可以指示同步方法。
  • 语法更加紧凑。
  • 强制将同步块拆分为单独的方法。

缺点:

  • 与此同步,因此外部人员也可以与其同步。
  • 将代码移到同步块之外比较困难。

同步块

优点:

  • 允许对锁使用私有变量,从而强制锁保留在类内。
  • 可以通过搜索变量的引用来找到同步块。

缺点:

  • 语法更复杂,因此使代码更难以阅读。

就我个人而言,我更喜欢将同步方法与仅关注需要同步的事物的类一起使用。这样的类应该尽可能小,这样应该很容易检查同步。其他人不需要关心同步。

的主要区别是,如果使用一个同步块可以锁定以外的物体上的这允许更加灵活。

假定有一个消息队列和多个消息生产者和消费者。我们不想生产商相互干扰,但消费者应该可以,而不必等待生产者检索消息。 所以,我们只是创建了一个对象

Object writeLock = new Object();

,从现在起的每一个生产者要添加新的消息,我们刚刚锁定该时间:

synchronized(writeLock){
  // do something
}

所以消费者可能仍然读取,并且生产商将被锁定。

<强>同步方式

同步方法具有两个效果。结果 首先,当一个线程正在执行的对象同步方法,来调用同步对于相同的对象块(挂起执行),直到第一线程的方法的全部其他线程与该对象进行。

其次,当一个同步方法退出时,它自动地建立一个之前发生有用于相同对象的同步方法的任何后续调用关系。这保证了更改对象的状态是所有线程可见。

注意,构造函数不能被同步 - 使用带有构造synchronized关键字是一个语法错误。同步构造没有意义的,因为正在建设中,而它仅仅是创建一个对象的线程应该能够访问它。

<强> synchronized声明

与同步方法,同步语句必须指定提供的内部锁对象:大多数情况下我使用它来同步访问列表或地图,但我不想阻止访问对象的所有方法。

问:内在锁和同步 同步是围绕被称为内在锁或监视器锁定内部实体建造。 (API规范通常是指这个实体简称为“显示器”。)内在锁在同步的两个方面发挥作用:执行一个对象的状态和建立之前发生是能见度的关系至关重要独占访问。

每个对象具有与之相关联的本征锁。按照惯例,需要一个对象的字段独家一致的访问一个线程访问之前,获取物体的内部锁,然后当它与他们所做的释放内部锁。一个线程被说成自己的,它已经收购了锁和释放锁的时间之间的内在锁。只要一个线程拥有一个内部锁,没有其他线程可以获取同样的锁。当它试图获取锁,其他的线程将阻塞。

package test;

public class SynchTest implements Runnable {  
    private int c = 0;

    public static void main(String[] args) {
        new SynchTest().test();
    }

    public void test() {
        // Create the object with the run() method
        Runnable runnable = new SynchTest();
        Runnable runnable2 = new SynchTest();
        // Create the thread supplying it with the runnable object
        Thread thread = new Thread(runnable,"thread-1");
        Thread thread2 = new Thread(runnable,"thread-2");
//      Here the key point is passing same object, if you pass runnable2 for thread2,
//      then its not applicable for synchronization test and that wont give expected
//      output Synchronization method means "it is not possible for two invocations
//      of synchronized methods on the same object to interleave"

        // Start the thread
        thread.start();
        thread2.start();
    }

    public synchronized  void increment() {
        System.out.println("Begin thread " + Thread.currentThread().getName());
        System.out.println(this.hashCode() + "Value of C = " + c);
//      If we uncomment this for synchronized block, then the result would be different
//      synchronized(this) {
            for (int i = 0; i < 9999999; i++) {
                c += i;
            }
//      }
        System.out.println("End thread " + Thread.currentThread().getName());
    }

//    public synchronized void decrement() {
//        System.out.println("Decrement " + Thread.currentThread().getName());
//    }

    public int value() {
        return c;
    }

    @Override
    public void run() {
        this.increment();
    }
}

交叉检查不同的输出与同步方法,块和不同步。

注意:<强>静态同步方法和块类对象上工作

public class MyClass {
   // locks MyClass.class
   public static synchronized void foo() {
// do something
   }

   // similar
   public static void foo() {
      synchronized(MyClass.class) {
// do something
      }
   }
}

当Java编译器转换源代码到字节代码,它处理同步方法和同步块很不同。

当的JVM执行一个同步方法,正在执行的线程标识,所述方法的method_info结构具有ACC_SYNCHRONIZED标志设置,则它自动获取对象的锁,调用该方法,并释放该锁。如果发生异常,线程自动释放该锁。

同步的方法块,而另一方面,绕过JVM的内置用于获取对象的锁和异常处理和要求的功能被明确地写在字节代码的支持。如果用synchronized块读取的方法的字节代码,你会看到十几额外的操作来管理此功能。

此示出了呼叫,以产生两个同步方法和同步块:

public class SynchronizationExample {
    private int i;

    public synchronized int synchronizedMethodGet() {
        return i;
    }

    public int synchronizedBlockGet() {
        synchronized( this ) {
            return i;
        }
    }
}

synchronizedMethodGet()方法生成以下字节代码:

0:  aload_0
1:  getfield
2:  nop
3:  iconst_m1
4:  ireturn

和这里的从synchronizedBlockGet()方法的字节代码:

0:  aload_0
1:  dup
2:  astore_1
3:  monitorenter
4:  aload_0
5:  getfield
6:  nop
7:  iconst_m1
8:  aload_1
9:  monitorexit
10: ireturn
11: astore_2
12: aload_1
13: monitorexit
14: aload_2
15: athrow

同步方法和块之间的一个显著区别在于,同步块通常降低锁的范围。由于锁定的范围是成反比的性能,它始终是更好地锁定的唯一代码关键部分。一个使用同步块的最好的例子是双重检查锁定在Singleton模式其中,代替锁定整个getInstance()方法我们只锁定的,其被用来创建Singleton实例代码临界区。这可以提高性能急剧因为锁定只需要一次或两次。

在使用synchronized方法,你需要,如果你混合静态同步和非同步的静态方法格外小心。

大多数情况下我使用它来同步访问列表或地图,但我不想阻止访问对象的所有方法。

在下面的代码一个线程修改列表将不阻塞等待被修改地图的螺纹。如果方法进行了在物体上的同步然后每个方法将必须等待,即使修改他们正在不会冲突。

private List<Foo> myList = new ArrayList<Foo>();
private Map<String,Bar) myMap = new HashMap<String,Bar>();

public void put( String s, Bar b ) {
  synchronized( myMap ) {
    myMap.put( s,b );
    // then some thing that may take a while like a database access or RPC or notifying listeners
  }
}

public void hasKey( String s, ) {
  synchronized( myMap ) {
    myMap.hasKey( s );
  }
}

public void add( Foo f ) {
  synchronized( myList ) {
    myList.add( f );
// then some thing that may take a while like a database access or RPC or notifying listeners
  }
}

public Thing getMedianFoo() {
  Foo med = null;
  synchronized( myList ) {
    Collections.sort(myList);
    med = myList.get(myList.size()/2); 
  }
  return med;
}

使用synchronized块,你可以有多个同步器,使多个同时但不冲突的东西都可以在同一时间去。

同步方法可以使用反射API被检查。这可以是用于测试一些合同,如在模型中的所有方法都是同步的有用

下面的片断输出哈希表的所有的同步方法:

for (Method m : Hashtable.class.getMethods()) {
        if (Modifier.isSynchronized(m.getModifiers())) {
            System.out.println(m);
        }
}

常使用上的方法级的锁是太粗鲁。为什么锁定一块不通过锁定一整方法访问任何共享资源的代码。由于每个对象都有一个锁,你可以创建实现块级同步虚拟对象。 的块水平是更有效的,因为它不锁定整个方法。

下面一些示例

方式等级

class MethodLevel {

  //shared among threads
SharedResource x, y ;

public void synchronized method1() {
   //multiple threads can't access
}
public void synchronized method2() {
  //multiple threads can't access
}

 public void method3() {
  //not synchronized
  //multiple threads can access
 }
}

阻止等级

class BlockLevel {
  //shared among threads
  SharedResource x, y ;

  //dummy objects for locking
  Object xLock = new Object();
  Object yLock = new Object();

    public void method1() {
     synchronized(xLock){
    //access x here. thread safe
    }

    //do something here but don't use SharedResource x, y
    // because will not be thread-safe
     synchronized(xLock) {
       synchronized(yLock) {
      //access x,y here. thread safe
      }
     }

     //do something here but don't use SharedResource x, y
     //because will not be thread-safe
    }//end of method1
 }

<强> [编辑]

有关像CollectionVector HashtableArrayListHashMap不是,你需要设置synchronized关键字或调用类别同步方法它们同步:

Map myMap = Collections.synchronizedMap (myMap); // single lock for the entire map
List myList = Collections.synchronizedList (myList); // single lock for the entire list

唯一的区别: 同步块允许颗粒锁不同步的方法

基本上 synchronized 阻止或方法已用于编写线的安全代码通过避免存有不一致的错误。

这个问题是非常古老以及许多事情已经改变了过去的7年。新的方案编制结构已经引入线的安全。

你可以实现的线安全通过使用先进的并发API而不是的 synchronied 块。这个文件 页面 提供了很好的编程结构达到线的安全。

锁定对象 支持锁定的惯用语,简化许多并发的应用程序。

遗嘱执行人 定义一个高级别API为启动和管理的螺纹。执行者的实现提供由java。工具.并行提供的线的游泳池管理适用于大规模的应用。

并发集合 使其更易于管理大型集的数据,并且可以大大减少需要同步。

原子变量 有的功能,尽量减少同步,并有助于避免存储器的一致性错误。

ThreadLocalRandom (在JAVA7)提供了有效率地产生的伪随机数字从多线程。

更好的替代同步 ReentrantLock, ,其使用 Lock API

一个重入相互排斥的锁相同的基本行为和语义隐含的监测锁定访问的使用的同步方法和声明,但延长的能力。

例锁:

class X {
   private final ReentrantLock lock = new ReentrantLock();
   // ...

   public void m() {
     lock.lock();  // block until condition holds
     try {
       // ... method body
     } finally {
       lock.unlock()
     }
   }
 }

请参阅 java。工具.并发java。工具.并行。原子 软件包也用于其他方案结构。

参见此相关的问题:

同步vs锁

同步方法用于锁定的所有对象 同步块被用于锁定特定对象

在一般这些大多是不是被明确的有关活动正用于VS隐含此对象的对象监视器相同的其他。 synchronized方法,我觉得有时忽略的一个缺点是,在使用“this”引用对您同步离开开放的外部对象锁定对同一对象的可能性。这可以是一个非常微妙的错误,如果你碰到它。同步在内部明确的对象或其他现有的字段可避免此问题,完全包封的同步。

正如已经说过的在这里同步块可以使用用户定义的变量作为锁定对象,当同步功能只有“这个”使用。当然,你可以用它应该是同步的功能区操作。 但是大家都说同步功能和块覆盖整个功能没有什么区别使用“this”的锁定对象。这是不正确的,不同的是,这将在两种情况下会产生字节码。在同步块使用的情况下,应分配保持提及“这个”局部变量。而作为结果,我们需要有一点点大的大小的功能(如果您有功能只有极少数不相关)。

您可以在这里找到差异的更详细的解释: http://www.artima.com/insidejvm/ed2/threadsynchP.html

在的同步方法的情况下,锁将被上的对象获取的。但是,如果你具有同步块去必须指定在其上的锁将被获取的对象的选项。

示例:

    Class Example {
    String test = "abc";
    // lock will be acquired on String  test object.
    synchronized (test) {
        // do something
    }

   lock will be acquired on Example Object
   public synchronized void testMethod() {
     // do some thing
   } 

   }

我知道这是一个老问题,但我在这里的答复快速阅读,我真的没有看到任何人提到,在次synchronized方法可能是在错误
从Java并发实践(第72):

public class ListHelper<E> {
  public List<E> list = Collections.syncrhonizedList(new ArrayList<>());
...

public syncrhonized boolean putIfAbsent(E x) {
 boolean absent = !list.contains(x);
if(absent) {
 list.add(x);
}
return absent;
}

上面的代码具有作为线程安全的外观即可。然而,在现实中却并非如此。在这种情况下是在该类的实例中得到的锁。然而,可能的是在列表以由另一个线程不使用该方法进行修改。正确的做法是使用

public boolean putIfAbsent(E x) {
 synchronized(list) {
  boolean absent = !list.contains(x);
  if(absent) {
    list.add(x);
  }
  return absent;
}
}

在上面的代码会阻塞的所有线程试图修改的从修改列表,直到上述同步块已经完成列表

作为一个实际问题,超过同步块同步方法的优点是,它们是更白痴抗性;因为你不能选择任意对象锁定,你不能滥用同步方法语法做愚蠢的事情,例如把基于文字或锁定上,但未通过螺纹之下变出了一个可变字段的内容。

在另一方面,与同步方法不能保护锁从通过任何线程,可以得到对对象的引用得到获得的。

因此,使用同步为上的方法的改性剂是在保护你牛orkers从伤害自己更好,而在与私人最终锁定对象一起使用的同步块是在保护自己的代码从奶牛-orkers更好

从Java规范概要: http://www.cs.cornell.edu/andru/javaspec/17 .doc.html

  

在同步语句(§14.17)计算对一个对象的引用;   然后尝试在该对象上执行锁定动作,并且不   继续进行,直到锁定动作已成功完成。 ...

     

一个同步方法(§8.4.3.5)自动执行锁定动作   当它被调用;不执行它的身体,直到锁定动作有   成功完成。 如果该方法是一个实例方法下,它   锁定与实例相关的锁就为其调用   (即,将执行期间被称为此物体   该方法的主体)。 如果该方法是静态的下,它锁定   锁与表示在该类的类对象相关联   该方法被定义。 ...

根据这些描述,我会说,大多数以前的答案是正确的,同步的方法可能是静态方法,你本来要弄清楚如何让代表类的“Class对象特别有用,其中所述方法被定义。“

编辑:我本来以为这些都是实际的Java规范的报价。明确的是该网页是规范的摘要/解释

太长了; 都不使用 synchronized 修饰符也不 synchronized(this){...} 表达但是 synchronized(myLock){...} 在哪里 myLock 是保存私有对象的最终实例字段。


使用之间的区别 synchronized 方法声明上的修饰符和 synchronized(..){ } 方法体中的表达式是这样的:

  • synchronized 方法签名上指定的修饰符
    1. 在生成的 JavaDoc 中可见,
    2. 可以通过编程方式确定 反射 当测试方法的修饰符时 修饰符.SYNCHRONIZED,
    3. 与相比,需要更少的打字和缩进 synchronized(this) { .... }, , 和
    4. (取决于您的 IDE)在类大纲和代码完成中可见,
    5. 使用 this 在非静态方法上声明时,对象作为锁;在静态方法上声明时,对象作为封闭类。
  • synchronized(...){...} 表达方式可以让你
    1. 仅同步方法主体部分的执行,
    2. 在构造函数或 (静止的)初始化块,
    3. 选择控制同步访问的锁对象。

然而,使用 synchronized 修饰语或 synchronized(...) {...}this 作为锁对象(如 synchronized(this) {...}),也有同样的缺点。两者都使用它自己的实例作为要同步的锁对象。这是危险的,因为不仅是物体本身,而且 任何 持有对该对象的引用的其他外部对象/代码也可以将其用作同步锁,但具有潜在的严重副作用(性能下降和 僵局).

因此,最佳实践是既不使用 synchronized 修饰符也不 synchronized(...) 结合表达 this 作为锁对象,但是该对象私有的锁对象。例如:

public class MyService {
    private final lock = new Object();

    public void doThis() {
       synchronized(lock) {
          // do code that requires synchronous execution
        }
    }

    public void doThat() {
       synchronized(lock) {
          // do code that requires synchronous execution
        }
    }
}

您还可以使用多个锁对象,但需要特别注意以确保嵌套使用时不会导致死锁。

public class MyService {
    private final lock1 = new Object();
    private final lock2 = new Object();

    public void doThis() {
       synchronized(lock1) {
          synchronized(lock2) {
              // code here is guaranteed not to be executes at the same time
              // as the synchronized code in doThat() and doMore().
          }
    }

    public void doThat() {
       synchronized(lock1) {
              // code here is guaranteed not to be executes at the same time
              // as the synchronized code in doThis().
              // doMore() may execute concurrently
        }
    }

    public void doMore() {
       synchronized(lock2) {
              // code here is guaranteed not to be executes at the same time
              // as the synchronized code in doThis().
              // doThat() may execute concurrently
        }
    }
}

我想这个问题是关于之间的区别 线程安全单例使用双重检查锁定进行延迟初始化. 。当我需要实现一些特定的单例时,我总是参考这篇文章。

嗯,这是一个 线程安全单例:

// Java program to create Thread Safe 
// Singleton class 
public class GFG  
{ 
  // private instance, so that it can be 
  // accessed by only by getInstance() method 
  private static GFG instance; 

  private GFG()  
  { 
    // private constructor 
  } 

 //synchronized method to control simultaneous access 
  synchronized public static GFG getInstance()  
  { 
    if (instance == null)  
    { 
      // if instance is null, initialize 
      instance = new GFG(); 
    } 
    return instance; 
  } 
} 

优点:

  1. 延迟初始化是可能的。

  2. 它是线程安全的。

缺点:

  1. getInstance() 方法是同步的,因此会导致性能下降,因为多个线程无法同时访问它。

这是一个 使用双重检查锁定进行延迟初始化:

// Java code to explain double check locking 
public class GFG  
{ 
  // private instance, so that it can be 
  // accessed by only by getInstance() method 
  private static GFG instance; 

  private GFG()  
  { 
    // private constructor 
  } 

  public static GFG getInstance() 
  { 
    if (instance == null)  
    { 
      //synchronized block to remove overhead 
      synchronized (GFG.class) 
      { 
        if(instance==null) 
        { 
          // if instance is null, initialize 
          instance = new GFG(); 
        } 

      } 
    } 
    return instance; 
  } 
} 

优点:

  1. 延迟初始化是可能的。

  2. 它也是线程安全的。

  3. 克服了由于synchronized关键字导致的性能下降。

缺点:

  1. 第一次,它会影响性能。

  2. 作为缺点。双检查锁定方法是可轴承的,因此可以用于高性能多线程应用程序。

更详细的内容请参考这篇文章:

https://www.geeksforgeeks.org/java-singleton-design-pattern-practices-examples/

同步有螺纹。 1)在一个线程它不工作不会使用同步(这一点)。与(本)同步使用当前线程作为锁定螺纹对象。由于每个线程都是独立于其他线程的,还有同步的NO协调。 2)的代码显示,在Java 1.6的Mac上的方法同步不起作用测试。 3)同步的(lockObj)其中lockObj是同步上,将工作的所有线程的公共共享对象。 4)ReenterantLock.lock()和.unlock()的工作。请参阅Java教程这一点。

下面的代码显示这些点。它还包含将被替换为ArrayList中的线程安全的载体,表明许多线程加入到Vector不会丢失任何信息,而用一个ArrayList同样可以丢失信息。 0)当前代码显示的信息损失,由于竞态条件 A)注释标记为A线的电流,并取消它上面的一条线,然后运行,方法失去数据,但它不应该。 B)反向步骤A中,取消B和//结束块}。然后运行看效果不会丢失数据 C)注释掉B,取消注释C.运行,见上同步(这)失去数据,如所预期。 没有足够的时间来完成所有的变化,希望这有助于。 如果同步上(本),或方法同步作品,请注明您测试的是什么版本的Java和操作系统。谢谢你。

import java.util.*;

/** RaceCondition - Shows that when multiple threads compete for resources 
     thread one may grab the resource expecting to update a particular 
     area but is removed from the CPU before finishing.  Thread one still 
     points to that resource.  Then thread two grabs that resource and 
     completes the update.  Then thread one gets to complete the update, 
     which over writes thread two's work.
     DEMO:  1) Run as is - see missing counts from race condition, Run severa times, values change  
            2) Uncomment "synchronized(countLock){ }" - see counts work
            Synchronized creates a lock on that block of code, no other threads can 
            execute code within a block that another thread has a lock.
        3) Comment ArrayList, unComment Vector - See no loss in collection
            Vectors work like ArrayList, but Vectors are "Thread Safe"
         May use this code as long as attribution to the author remains intact.
     /mf
*/ 

public class RaceCondition {
    private ArrayList<Integer> raceList = new ArrayList<Integer>(); // simple add(#)
//  private Vector<Integer> raceList = new Vector<Integer>(); // simple add(#)

    private String countLock="lock";    // Object use for locking the raceCount
    private int raceCount = 0;        // simple add 1 to this counter
    private int MAX = 10000;        // Do this 10,000 times
    private int NUM_THREADS = 100;    // Create 100 threads

    public static void main(String [] args) {
    new RaceCondition();
    }

    public RaceCondition() {
    ArrayList<Thread> arT = new ArrayList<Thread>();

    // Create thread objects, add them to an array list
    for( int i=0; i<NUM_THREADS; i++){
        Thread rt = new RaceThread( ); // i );
        arT.add( rt );
    }

    // Start all object at once.
    for( Thread rt : arT ){
        rt.start();
    }

    // Wait for all threads to finish before we can print totals created by threads
    for( int i=0; i<NUM_THREADS; i++){
        try { arT.get(i).join(); }
        catch( InterruptedException ie ) { System.out.println("Interrupted thread "+i); }
    }

    // All threads finished, print the summary information.
    // (Try to print this informaiton without the join loop above)
    System.out.printf("\nRace condition, should have %,d. Really have %,d in array, and count of %,d.\n",
                MAX*NUM_THREADS, raceList.size(), raceCount );
    System.out.printf("Array lost %,d. Count lost %,d\n",
             MAX*NUM_THREADS-raceList.size(), MAX*NUM_THREADS-raceCount );
    }   // end RaceCondition constructor



    class RaceThread extends Thread {
    public void run() {
        for ( int i=0; i<MAX; i++){
        try {
            update( i );        
        }    // These  catches show when one thread steps on another's values
        catch( ArrayIndexOutOfBoundsException ai ){ System.out.print("A"); }
        catch( OutOfMemoryError oome ) { System.out.print("O"); }
        }
    }

    // so we don't lose counts, need to synchronize on some object, not primitive
    // Created "countLock" to show how this can work.
    // Comment out the synchronized and ending {, see that we lose counts.

//    public synchronized void update(int i){   // use A
    public void update(int i){                  // remove this when adding A
//      synchronized(countLock){            // or B
//      synchronized(this){             // or C
        raceCount = raceCount + 1;
        raceList.add( i );      // use Vector  
//          }           // end block for B or C
    }   // end update

    }   // end RaceThread inner class


} // end RaceCondition outter class
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top