一般来说,除了显式地显示正在使用的对象的监视器与隐式的 this 对象之外,这些大多是相同的。 我认为有时会被忽视的同步方法的一个缺点是,在使用“this”引用进行同步时,可能会导致外部对象锁定同一对象。 如果您遇到它,这可能是一个非常微妙的错误。 在内部显式对象或其他现有字段上进行同步可以避免此问题,从而完全封装同步。
In general these are mostly the same other than being explicit about the object's monitor that's being used vs the implicit this object. One downside of synchronized methods that I think is sometimes overlooked is that in using the "this" reference to synchronize on you are leaving open the possibility of external objects locking on the same object. That can be a very subtle bug if you run into it. Synchronizing on an internal explicit Object or other existing field can avoid this issue, completely encapsulating the synchronization.
As already said here synchronized block can use user-defined variable as lock object, when synchronized function uses only "this". And of course you can manipulate with areas of your function which should be synchronized.
But everyone says that no difference between synchronized function and block which covers whole function using "this" as lock object. That is not true, difference is in byte code which will be generated in both situations. In case of synchronized block usage should be allocated local variable which holds reference to "this". And as result we will have a little bit larger size for function (not relevant if you have only few number of functions).
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
}
}
In case of synchronized methods, lock will be acquired on an Object. But if you go with synchronized block you have an option to specify an object on which the lock will be acquired.
Example :
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
}
}
I know this is an old question, but with my quick read of the responses here, I didn't really see anyone mention that at times a synchronized method may be the wrong lock.
From Java Concurrency In Practice (pg. 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;
}
The above code has the appearance of being thread-safe. However, in reality it is not. In this case the lock is obtained on the instance of the class. However, it is possible for the list to be modified by another thread not using that method. The correct approach would be to use
As a practical matter, the advantage of synchronized methods over synchronized blocks is that they are more idiot-resistant; because you can't choose an arbitrary object to lock on, you can't misuse the synchronized method syntax to do stupid things like locking on a string literal or locking on the contents of a mutable field that gets changed out from under the threads.
On the other hand, with synchronized methods you can't protect the lock from getting acquired by any thread that can get a reference to the object.
So using synchronized as a modifier on methods is better at protecting your cow-orkers from hurting themselves, while using synchronized blocks in conjunction with private final lock objects is better at protecting your own code from the cow-orkers.
The synchronized statement (§14.17) computes a reference to an object;
it then attempts to perform a lock action on that object and does not
proceed further until the lock action has successfully completed. ...
A synchronized method (§8.4.3.5) automatically performs a lock action
when it is invoked; its body is not executed until the lock action has
successfully completed. If the method is an instance method, it
locks the lock associated with the instance for which it was invoked
(that is, the object that will be known as this during execution of
the body of the method). If the method is static, it locks the
lock associated with the Class object that represents the class in
which the method is defined. ...
Based on these descriptions, I would say most previous answers are correct, and a synchronized method might be particularly useful for static methods, where you would otherwise have to figure out how to get the "Class object that represents the class in which the method was defined."
Edit: I originally thought these were quotes of the actual Java spec. Clarified that this page is just a summary/explanation of the spec
因此,最佳实践是既不要使用 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
}
}
}
TLDR; Neither use the synchronized modifier nor the synchronized(this){...} expression but synchronized(myLock){...} where myLock is a final instance field holding a private object.
The difference between using the synchronized modifier on the method declaration and the synchronized(..){ } expression in the method body are this:
The synchronized modifier specified on the method's signature
requires less typing and indention compared to synchronized(this) { .... }, and
(depending on your IDE) is visible in the class outline and code completion,
uses the this object as lock when declared on non-static method or the enclosing class when declared on a static method.
The synchronized(...){...} expression allows you
to only synchronize the execution of parts of a method's body,
to be used within a constructor or a (static) initialization block,
to choose the lock object which controls the synchronized access.
However, using the synchronized modifier or synchronized(...) {...} with this as the lock object (as in synchronized(this) {...}), have the same disadvantage. Both use it's own instance as the lock object to synchronize on. This is dangerous because not only the object itself but any other external object/code that holds a reference to that object can also use it as a synchronization lock with potentially severe side effects (performance degradation and deadlocks).
Therefore best practice is to neither use the synchronized modifier nor the synchronized(...) expression in conjunction with this as lock object but a lock object private to this object. For example:
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
}
}
}
You can also use multiple lock objects but special care needs to be taken to ensure this does not result in deadlocks when used nested.
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;
}
}
优点:
可以进行延迟初始化。
它是线程安全的。
缺点:
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;
}
}
I suppose this question is about the difference between Thread Safe Singleton and Lazy initialization with Double check locking. I always refer to this article when I need to implement some specific singleton.
Well, this is a Thread Safe Singleton:
// 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;
}
}
Pros:
Lazy initialization is possible.
It is thread safe.
Cons:
getInstance() method is synchronized so it causes slow performance as multiple threads can’t access it simultaneously.
This is a Lazy initialization with Double check locking:
// 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;
}
}
Pros:
Lazy initialization is possible.
It is also thread safe.
Performance reduced because of synchronized keyword is overcome.
Cons:
First time, it can affect performance.
As cons. of double check locking method is bearable so it can be
used for high performance multi-threaded applications.
以下代码显示了这些要点。 它还包含线程安全的 Vector,它将替代 ArrayList,以表明添加到 Vector 的许多线程不会丢失任何信息,而使用 ArrayList 则可能会丢失信息。
0) 当前代码显示由于竞争条件导致信息丢失
A)注释当前标记的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
Synchronizing with threads.
1) NEVER use synchronized(this) in a thread it doesn't work. Synchronizing with (this) uses the current thread as the locking thread object. Since each thread is independent of other threads, there is NO coordination of synchronization.
2) Tests of code show that in Java 1.6 on a Mac the method synchronization does not work.
3) synchronized(lockObj) where lockObj is a common shared object of all threads synchronizing on it will work.
4) ReenterantLock.lock() and .unlock() work. See Java tutorials for this.
The following code shows these points. It also contains the thread-safe Vector which would be substituted for the ArrayList, to show that many threads adding to a Vector do not lose any information, while the same with an ArrayList can lose information.
0) Current code shows loss of information due to race conditions
A) Comment the current labeled A line, and uncomment the A line above it, then run, method loses data but it shouldn't.
B) Reverse step A, uncomment B and // end block }. Then run to see results no loss of data
C) Comment out B, uncomment C. Run, see synchronizing on (this) loses data, as expected.
Don't have time to complete all the variations, hope this helps.
If synchronizing on (this), or the method synchronization works, please state what version of Java and OS you tested. Thank you.
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
// 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
}
Can anyone tell me the advantage of the synchronized method over the synchronized block with an example? Thanks.
There is not a clear advantage of using synchronized method over the block.
Perhaps the only one ( but I wouldn't call it an advantage ) is you don't need to include the object reference this.
Method:
public synchronized void method() { // blocks "this" from here....
...
...
...
} // to here
Block:
public void method() {
synchronized( this ) { // blocks "this" from here ....
....
....
....
} // to here...
}
See? No advantage at all.
Blocks do have advantages over methods though, mostly in flexibility because you can use another object as lock whereas syncing the method would lock the entire object.
// Using specific locks
Object inputLock = new Object();
Object outputLock = new Object();
private void someInputRelatedWork() {
synchronized(inputLock) {
...
}
}
private void someOutputRelatedWork() {
synchronized(outputLock) {
...
}
}
Also if the method grows you can still keep the synchronized section separated:
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
}
The only real difference is that a synchronized block can choose which object it synchronizes on. A synchronized method can only use 'this' (or the corresponding Class instance for a synchronized class method). For example, these are semantically equivalent:
The latter is more flexible since it can compete for the associated lock of any object, often a member variable. It's also more granular because you could have concurrent code executing before and after the block but still within the method. Of course, you could just as easily use a synchronized method by refactoring the concurrent code into separate non-synchronized methods. Use whichever makes the code more comprehensible.
Forces to split the synchronized blocks to separate methods.
Cons:
Synchronizes to this and so makes it possible to outsiders to synchronize to it too.
It is harder to move code outside the synchronized block.
Synchronized block
Pros:
Allows using a private variable for the lock and so forcing the lock to stay inside the class.
Synchronized blocks can be found by searching references to the variable.
Cons:
The syntax is more complicated and so makes the code harder to read.
Personally I prefer using synchronized methods with classes focused only to the thing needing synchronization. Such class should be as small as possible and so it should be easy to review the synchronization. Others shouldn't need to care about synchronization.
The main difference is that if you use a synchronized block you may lock on an object other than this which allows to be much more flexible.
Assume you have a message queue and multiple message producers and consumers. We don't want producers to interfere with each other, but the consumers should be able to retrieve messages without having to wait for the producers.
So we just create an object
Object writeLock = new Object();
And from now on every time a producers wants to add a new message we just lock on that:
synchronized(writeLock){
// do something
}
So consumers may still read, and producers will be locked.
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();
}
}
使用同步方法、块和不同步方法交叉检查不同的输出。
Synchronized method
Synchronized methods have two effects.
First, when one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.
Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads.
Note that constructors cannot be synchronized — using the synchronized keyword with a constructor is a syntax error. Synchronizing constructors doesn't make sense, because only the thread that creates an object should have access to it while it is being constructed.
Synchronized Statement
Unlike synchronized methods, synchronized statements must specify the object that provides the intrinsic lock: Most often I use this to synchronize access to a list or map but I don't want to block access to all methods of the object.
Q: Intrinsic Locks and Synchronization
Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. (The API specification often refers to this entity simply as a "monitor.") Intrinsic locks play a role in both aspects of synchronization: enforcing exclusive access to an object's state and establishing happens-before relationships that are essential to visibility.
Every object has an intrinsic lock associated with it. By convention, a thread that needs exclusive and consistent access to an object's fields has to acquire the object's intrinsic lock before accessing them, and then release the intrinsic lock when it's done with them. A thread is said to own the intrinsic lock between the time it has acquired the lock and released the lock. As long as a thread owns an intrinsic lock, no other thread can acquire the same lock. The other thread will block when it attempts to acquire the lock.
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();
}
}
Cross check different outputs with synchronized method, block and without synchronization.
public class MyClass {
// locks MyClass.class
public static synchronized void foo() {
// do something
}
// similar
public static void foo() {
synchronized(MyClass.class) {
// do something
}
}
}
Note: static synchronized methods and blocks work on the Class object.
public class MyClass {
// locks MyClass.class
public static synchronized void foo() {
// do something
}
// similar
public static void foo() {
synchronized(MyClass.class) {
// do something
}
}
}
public class SynchronizationExample {
private int i;
public synchronized int synchronizedMethodGet() {
return i;
}
public int synchronizedBlockGet() {
synchronized( this ) {
return i;
}
}
}
When java compiler converts your source code to byte code, it handles synchronized methods and synchronized blocks very differently.
When the JVM executes a synchronized method, the executing thread identifies that the method's method_info structure has the ACC_SYNCHRONIZED flag set, then it automatically acquires the object's lock, calls the method, and releases the lock. If an exception occurs, the thread automatically releases the lock.
Synchronizing a method block, on the other hand, bypasses the JVM's built-in support for acquiring an object's lock and exception handling and requires that the functionality be explicitly written in byte code. If you read the byte code for a method with a synchronized block, you will see more than a dozen additional operations to manage this functionality.
This shows calls to generate both a synchronized method and a synchronized block:
public class SynchronizationExample {
private int i;
public synchronized int synchronizedMethodGet() {
return i;
}
public int synchronizedBlockGet() {
synchronized( this ) {
return i;
}
}
}
The synchronizedMethodGet() method generates the following byte code:
One significant difference between synchronized method and block is that, Synchronized block generally reduce scope of lock. As scope of lock is inversely proportional to performance, its always better to lock only critical section of code. One of the best example of using synchronized block is double checked locking in Singleton pattern where instead of locking whole getInstance() method we only lock critical section of code which is used to create Singleton instance. This improves performance drastically because locking is only required one or two times.
While using synchronized methods, you will need to take extra care if you mix both static synchronized and non-static synchronized methods.
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;
}
Most often I use this to synchronize access to a list or map but I don't want to block access to all methods of the object.
In the following code one thread modifying the list will not block waiting for a thread that is modifying the map. If the methods were synchronized on the object then each method would have to wait even though the modifications they are making would not conflict.
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;
}
for (Method m : Hashtable.class.getMethods()) {
if (Modifier.isSynchronized(m.getModifiers())) {
System.out.println(m);
}
}
Synchronized methods can be checked using reflection API. This can be useful for testing some contracts, such as all methods in model are synchronized.
The following snippet prints all the synchronized methods of Hashtable:
for (Method m : Hashtable.class.getMethods()) {
if (Modifier.isSynchronized(m.getModifiers())) {
System.out.println(m);
}
}
Important note on using the synchronized block: careful what you use as lock object!
The code snippet from user2277816 above illustrates this point in that a reference to a string literal is used as locking object.
Realize that string literals are automatically interned in Java and you should begin to see the problem: every piece of code that synchronizes on the literal "lock", shares the same lock! This can easily lead to deadlocks with completely unrelated pieces of code.
It is not just String objects that you need to be careful with. Boxed primitives are also a danger, since autoboxing and the valueOf methods can reuse the same objects, depending on the value.
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
}
Map myMap = Collections.synchronizedMap (myMap); // single lock for the entire map
List myList = Collections.synchronizedList (myList); // single lock for the entire list
Often using a lock on a method level is too rude. Why lock up a piece of code that does not access any shared resources by locking up an entire method. Since each object has a lock, you can create dummy objects to implement block level synchronization. The block level is more efficient because it does not lock the whole method.
Here some example
Method Level
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
}
}
Block Level
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
}
[Edit]
For Collection like Vector and Hashtable they are synchronized when ArrayList or HashMap are not and you need set synchronized keyword or invoke Collections synchronized method:
Map myMap = Collections.synchronizedMap (myMap); // single lock for the entire map
List myList = Collections.synchronizedList (myList); // single lock for the entire list
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}
The only difference : synchronized blocks allows granular locking unlike synchronized method
Basically synchronized block or methods have been used to write thread safe code by avoiding memory inconsistency errors.
This question is very old and many things have been changed during last 7 years.
New programming constructs have been introduced for thread safety.
You can achieve thread safety by using advanced concurrency API instead of synchronied blocks. This documentation page provides good programming constructs to achieve thread safety.
Lock Objects support locking idioms that simplify many concurrent applications.
Executors define a high-level API for launching and managing threads. Executor implementations provided by java.util.concurrent provide thread pool management suitable for large-scale applications.
Concurrent Collections make it easier to manage large collections of data, and can greatly reduce the need for synchronization.
Atomic Variables have features that minimize synchronization and help avoid memory consistency errors.
ThreadLocalRandom (in JDK 7) provides efficient generation of pseudorandom numbers from multiple threads.
Better replacement for synchronized is ReentrantLock, which uses Lock API
A reentrant mutual exclusion Lock with the same basic behavior and semantics as the implicit monitor lock accessed using synchronized methods and statements, but with extended capabilities.
Example with locks:
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}
发布评论
评论(23)
同步方法用于锁定所有对象
同步块用于锁定特定对象
Synchronized method is used for lock all the objects
Synchronized block is used to lock specific object
一般来说,除了显式地显示正在使用的对象的监视器与隐式的 this 对象之外,这些大多是相同的。 我认为有时会被忽视的同步方法的一个缺点是,在使用“this”引用进行同步时,可能会导致外部对象锁定同一对象。 如果您遇到它,这可能是一个非常微妙的错误。 在内部显式对象或其他现有字段上进行同步可以避免此问题,从而完全封装同步。
In general these are mostly the same other than being explicit about the object's monitor that's being used vs the implicit this object. One downside of synchronized methods that I think is sometimes overlooked is that in using the "this" reference to synchronize on you are leaving open the possibility of external objects locking on the same object. That can be a very subtle bug if you run into it. Synchronizing on an internal explicit Object or other existing field can avoid this issue, completely encapsulating the synchronization.
正如这里已经说过的,当同步函数仅使用“this”时,同步块可以使用用户定义的变量作为锁定对象。 当然,您可以操纵应该同步的函数区域。
但每个人都说同步函数和使用“this”作为锁定对象覆盖整个函数的块之间没有区别。 事实并非如此,差异在于两种情况下都会生成的字节码。 在使用同步块的情况下,应分配保存对“this”的引用的局部变量。 因此,我们的函数大小会稍大一些(如果函数数量很少,则不相关)。
您可以在此处找到有关差异的更详细说明:
http://www.artima.com/insidejvm/ed2/threadsynchP.html
As already said here synchronized block can use user-defined variable as lock object, when synchronized function uses only "this". And of course you can manipulate with areas of your function which should be synchronized.
But everyone says that no difference between synchronized function and block which covers whole function using "this" as lock object. That is not true, difference is in byte code which will be generated in both situations. In case of synchronized block usage should be allocated local variable which holds reference to "this". And as result we will have a little bit larger size for function (not relevant if you have only few number of functions).
More detailed explanation of the difference you can find here:
http://www.artima.com/insidejvm/ed2/threadsynchP.html
在同步方法的情况下,将在对象上获取锁。 但是,如果您使用同步块,您可以选择指定将获取锁的对象。
例子 :
In case of synchronized methods, lock will be acquired on an Object. But if you go with synchronized block you have an option to specify an object on which the lock will be acquired.
Example :
我知道这是一个老问题,但通过快速阅读这里的回复,我并没有看到有人提到有时
同步
方法可能是错误锁。来自 Java 并发实践(第 72 页):
上面的代码表面上是线程安全的。 然而,事实上并非如此。 在这种情况下,锁是在类的实例上获得的。 但是,列表可能会被不使用该方法的另一个线程修改。 正确的方法是使用
上面的代码将阻止所有线程尝试修改列表修改列表,直到同步块完成。
I know this is an old question, but with my quick read of the responses here, I didn't really see anyone mention that at times a
synchronized
method may be the wrong lock.From Java Concurrency In Practice (pg. 72):
The above code has the appearance of being thread-safe. However, in reality it is not. In this case the lock is obtained on the instance of the class. However, it is possible for the list to be modified by another thread not using that method. The correct approach would be to use
The above code would block all threads trying to modify list from modifying the list until the synchronized block has completed.
实际上,同步方法相对于同步块的优点是它们更不易被白痴使用。 因为您无法选择要锁定的任意对象,所以您不能滥用同步方法语法来执行愚蠢的操作,例如锁定字符串文字或锁定从线程下更改的可变字段的内容。
另一方面,使用同步方法,您无法保护锁不被任何可以获得对象引用的线程获取。
因此,使用synchronized作为方法的修饰符可以更好地保护你的牛人免受伤害,而将synchronized块与私有最终锁定对象结合使用可以更好地保护你自己的代码免受牛人的伤害。
As a practical matter, the advantage of synchronized methods over synchronized blocks is that they are more idiot-resistant; because you can't choose an arbitrary object to lock on, you can't misuse the synchronized method syntax to do stupid things like locking on a string literal or locking on the contents of a mutable field that gets changed out from under the threads.
On the other hand, with synchronized methods you can't protect the lock from getting acquired by any thread that can get a reference to the object.
So using synchronized as a modifier on methods is better at protecting your cow-orkers from hurting themselves, while using synchronized blocks in conjunction with private final lock objects is better at protecting your own code from the cow-orkers.
来自 Java 规范摘要:
http://www.cs.cornell.edu/andru/javaspec/ 17.doc.html
基于这些描述,我想说以前的大多数答案都是正确的,并且同步方法可能对于静态方法特别有用,否则您必须弄清楚如何获取“代表其中类的类对象”该方法已被定义。”
编辑:我最初认为这些是实际 Java 规范的引用。 澄清此页面只是规范的摘要/解释
From a Java specification summary:
http://www.cs.cornell.edu/andru/javaspec/17.doc.html
Based on these descriptions, I would say most previous answers are correct, and a synchronized method might be particularly useful for static methods, where you would otherwise have to figure out how to get the "Class object that represents the class in which the method was defined."
Edit: I originally thought these were quotes of the actual Java spec. Clarified that this page is just a summary/explanation of the spec
TLDR; 既不要使用
synchronized
修饰符,也不要使用synchronized(this){...}
表达式,而是使用synchronized(myLock){。 ..}
其中myLock
是保存私有对象的最终实例字段。在方法声明上使用
synchronized
修饰符与在方法主体中使用synchronized(..){ }
表达式之间的区别如下:synchronized
方法签名上指定的修饰符synchronized(this) { .... }
相比,需要更少的打字和缩进,并且this
对象作为锁;在静态方法上声明时,使用封闭类作为锁。synchronized(...){...}
表达式允许您但是,使用
synchronized
修饰符或synchronized(...) {...}
以及this
作为锁定对象(如>synchronized(this) {...}
),也有同样的缺点。 两者都使用它自己的实例作为要同步的锁对象。 这是危险的,因为不仅对象本身,任何持有该对象引用的其他外部对象/代码也可以将其用作同步锁,从而带来潜在的严重副作用(性能下降和死锁)。因此,最佳实践是既不要使用
synchronized
修饰符,也不将synchronized(...)
表达式与this
结合使用作为锁对象,而是使用锁该对象私有的对象。 例如:您还可以使用多个锁对象,但需要特别注意以确保嵌套使用时不会导致死锁。
TLDR; Neither use the
synchronized
modifier nor thesynchronized(this){...}
expression butsynchronized(myLock){...}
wheremyLock
is a final instance field holding a private object.The difference between using the
synchronized
modifier on the method declaration and thesynchronized(..){ }
expression in the method body are this:synchronized
modifier specified on the method's signaturesynchronized(this) { .... }
, andthis
object as lock when declared on non-static method or the enclosing class when declared on a static method.synchronized(...){...}
expression allows youHowever, using the
synchronized
modifier orsynchronized(...) {...}
withthis
as the lock object (as insynchronized(this) {...}
), have the same disadvantage. Both use it's own instance as the lock object to synchronize on. This is dangerous because not only the object itself but any other external object/code that holds a reference to that object can also use it as a synchronization lock with potentially severe side effects (performance degradation and deadlocks).Therefore best practice is to neither use the
synchronized
modifier nor thesynchronized(...)
expression in conjunction withthis
as lock object but a lock object private to this object. For example:You can also use multiple lock objects but special care needs to be taken to ensure this does not result in deadlocks when used nested.
我想这个问题是关于线程安全单例和使用双重检查锁定的延迟初始化之间的区别。 当我需要实现一些特定的单例时,我总是参考这篇文章。
嗯,这是一个线程安全单例:
这是一个带有双重检查锁定的延迟初始化:
请参阅这篇文章了解更多详细信息:
https://www. geeksforgeeks.org/java-singleton-design-pattern-practices-examples/
I suppose this question is about the difference between Thread Safe Singleton and Lazy initialization with Double check locking. I always refer to this article when I need to implement some specific singleton.
Well, this is a Thread Safe Singleton:
This is a Lazy initialization with Double check locking:
Please refer to this article for more details:
https://www.geeksforgeeks.org/java-singleton-design-pattern-practices-examples/
与线程同步。
1)永远不要在不起作用的线程中使用synchronized(this)。 同步(this)使用当前线程作为锁定线程对象。 由于每个线程独立于其他线程,因此不存在同步协调。
2)代码测试表明,在Mac上的Java 1.6中,方法同步不起作用。
3)synchronized(lockObj) 其中lockObj是所有线程在其上同步的公共共享对象。
4) ReenterantLock.lock() 和 .unlock() 工作。 请参阅 Java 教程。
以下代码显示了这些要点。 它还包含线程安全的 Vector,它将替代 ArrayList,以表明添加到 Vector 的许多线程不会丢失任何信息,而使用 ArrayList 则可能会丢失信息。
0) 当前代码显示由于竞争条件导致信息丢失
A)注释当前标记的A行,并取消注释上面的A行,然后运行,方法会丢失数据,但它不应该丢失。
B) 反转步骤 A,取消注释 B 和 // 结束块 }。 然后运行查看结果没有数据丢失
C) 注释掉 B,取消注释 C。运行,请参阅同步(此)丢失数据,正如预期的那样。
没有时间完成所有变体,希望这会有所帮助。
如果同步(此)或方法同步有效,请说明您测试的 Java 和操作系统版本。 谢谢。
Synchronizing with threads.
1) NEVER use synchronized(this) in a thread it doesn't work. Synchronizing with (this) uses the current thread as the locking thread object. Since each thread is independent of other threads, there is NO coordination of synchronization.
2) Tests of code show that in Java 1.6 on a Mac the method synchronization does not work.
3) synchronized(lockObj) where lockObj is a common shared object of all threads synchronizing on it will work.
4) ReenterantLock.lock() and .unlock() work. See Java tutorials for this.
The following code shows these points. It also contains the thread-safe Vector which would be substituted for the ArrayList, to show that many threads adding to a Vector do not lose any information, while the same with an ArrayList can lose information.
0) Current code shows loss of information due to race conditions
A) Comment the current labeled A line, and uncomment the A line above it, then run, method loses data but it shouldn't.
B) Reverse step A, uncomment B and // end block }. Then run to see results no loss of data
C) Comment out B, uncomment C. Run, see synchronizing on (this) loses data, as expected.
Don't have time to complete all the variations, hope this helps.
If synchronizing on (this), or the method synchronization works, please state what version of Java and OS you tested. Thank you.
使用同步方法相对于块并没有明显的优势。
也许唯一的一个(但我不会称其为优点)是您不需要包含对象引用
this
。方法:
块:
看到了吗? 一点优势都没有。
不过,块do比方法有优势,主要是灵活性,因为您可以使用另一个对象作为锁,而同步方法将锁定整个对象。
比较:
vs.
另外,如果方法增长,您仍然可以将同步部分分开:
There is not a clear advantage of using synchronized method over the block.
Perhaps the only one ( but I wouldn't call it an advantage ) is you don't need to include the object reference
this
.Method:
Block:
See? No advantage at all.
Blocks do have advantages over methods though, mostly in flexibility because you can use another object as lock whereas syncing the method would lock the entire object.
Compare:
vs.
Also if the method grows you can still keep the synchronized section separated:
唯一真正的区别是同步块可以选择同步哪个对象。 同步方法只能使用
'this'
(或同步类方法的相应类实例)。 例如,它们在语义上是等价的:后者更灵活,因为它可以竞争任何对象(通常是成员变量)的关联锁。 它还更加精细,因为您可以在块之前和之后执行并发代码,但仍在方法内。 当然,您可以通过将并发代码重构为单独的非同步方法来轻松使用同步方法。 使用使代码更容易理解的那个。
The only real difference is that a synchronized block can choose which object it synchronizes on. A synchronized method can only use
'this'
(or the corresponding Class instance for a synchronized class method). For example, these are semantically equivalent:The latter is more flexible since it can compete for the associated lock of any object, often a member variable. It's also more granular because you could have concurrent code executing before and after the block but still within the method. Of course, you could just as easily use a synchronized method by refactoring the concurrent code into separate non-synchronized methods. Use whichever makes the code more comprehensible.
同步方法的
优点:
缺点:
同步块
优点:
缺点:
就我个人而言,我更喜欢将同步方法与仅关注需要同步的事物的类一起使用。 这样的类应该尽可能小,这样应该很容易检查同步。 其他人不需要关心同步。
Synchronized Method
Pros:
Cons:
Synchronized block
Pros:
Cons:
Personally I prefer using synchronized methods with classes focused only to the thing needing synchronization. Such class should be as small as possible and so it should be easy to review the synchronization. Others shouldn't need to care about synchronization.
主要区别在于,如果您使用同步块,您可以锁定除 this 之外的对象,这样可以更加灵活。
假设您有一个消息队列和多个消息生产者和消费者。 我们不希望生产者相互干扰,但消费者应该能够检索消息而不必等待生产者。
因此,我们只需创建一个对象
,从现在开始,每当生产者想要添加新消息时,我们只需锁定它:
因此消费者仍然可以读取,而生产者将被锁定。
The main difference is that if you use a synchronized block you may lock on an object other than this which allows to be much more flexible.
Assume you have a message queue and multiple message producers and consumers. We don't want producers to interfere with each other, but the consumers should be able to retrieve messages without having to wait for the producers.
So we just create an object
And from now on every time a producers wants to add a new message we just lock on that:
So consumers may still read, and producers will be locked.
同步方法
同步方法有两个作用。
首先,当一个线程正在执行对象的同步方法时,调用同一对象的同步方法的所有其他线程都会阻塞(挂起执行),直到第一个线程完成该对象。
其次,当同步方法退出时,它会自动与同一对象的同步方法的任何后续调用建立发生之前关系。 这保证了对象状态的更改对所有线程都是可见的。
请注意,构造函数不能同步——在构造函数中使用synchronized关键字是一个语法错误。 同步构造函数没有意义,因为只有创建对象的线程才能在构造对象时访问它。
同步语句
与同步方法不同,同步语句必须指定提供内在锁的对象:大多数情况下,我使用它来同步对列表或映射的访问,但我不想阻止对所有方法的访问的对象。
问:本质锁和同步
同步是围绕称为内在锁或监视器锁的内部实体构建的。 (API 规范通常将此实体简单地称为“监视器”。)内在锁在同步的两个方面都发挥着作用:强制对对象状态进行独占访问并建立对可见性至关重要的发生前关系。
每个对象都有一个与其关联的内在锁。 按照惯例,需要对对象字段进行独占和一致访问的线程必须在访问对象字段之前获取对象的内在锁,然后在访问完这些字段后释放内在锁。 线程在获取锁和释放锁之间被称为拥有固有锁。 只要一个线程拥有固有锁,其他线程就无法获取相同的锁。 当另一个线程尝试获取锁时,它将被阻塞。
使用同步方法、块和不同步方法交叉检查不同的输出。
Synchronized method
Synchronized methods have two effects.
First, when one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.
Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads.
Note that constructors cannot be synchronized — using the synchronized keyword with a constructor is a syntax error. Synchronizing constructors doesn't make sense, because only the thread that creates an object should have access to it while it is being constructed.
Synchronized Statement
Unlike synchronized methods, synchronized statements must specify the object that provides the intrinsic lock: Most often I use this to synchronize access to a list or map but I don't want to block access to all methods of the object.
Q: Intrinsic Locks and Synchronization
Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. (The API specification often refers to this entity simply as a "monitor.") Intrinsic locks play a role in both aspects of synchronization: enforcing exclusive access to an object's state and establishing happens-before relationships that are essential to visibility.
Every object has an intrinsic lock associated with it. By convention, a thread that needs exclusive and consistent access to an object's fields has to acquire the object's intrinsic lock before accessing them, and then release the intrinsic lock when it's done with them. A thread is said to own the intrinsic lock between the time it has acquired the lock and released the lock. As long as a thread owns an intrinsic lock, no other thread can acquire the same lock. The other thread will block when it attempts to acquire the lock.
Cross check different outputs with synchronized method, block and without synchronization.
注意:静态同步方法和块作用于 Class 对象。
Note: static synchronized methods and blocks work on the Class object.
当java编译器将源代码转换为字节代码时,它对同步方法和同步块的处理方式非常不同。
当JVM执行synchronized方法时,执行线程识别出该方法的method_info结构设置了ACC_SYNCHRONIZED标志,然后它自动获取该对象的锁,调用该方法,并释放该锁。 如果发生异常,线程会自动释放锁。
另一方面,同步方法块绕过了 JVM 对获取对象锁和异常处理的内置支持,并要求以字节代码显式编写该功能。 如果您阅读带有同步块的方法的字节代码,您将看到十多个附加操作来管理此功能。
这显示了生成同步方法和同步块的调用:
synchronizedMethodGet()
方法生成以下字节代码:以下是来自
synchronizedBlockGet()
方法的字节代码:同步方法和块之间的一个显着区别是,同步块通常会缩小锁的范围。 由于锁定范围与性能成反比,因此仅锁定代码的关键部分总是更好。 使用同步块的最佳示例之一是单例模式中的双重检查锁定 我们只锁定用于创建 Singleton 实例的关键代码部分,而不是锁定整个 getInstance() 方法。 这极大地提高了性能,因为只需要锁定一两次。
使用同步方法时,如果混合使用静态同步方法和非静态同步方法,则需要格外小心。
When java compiler converts your source code to byte code, it handles synchronized methods and synchronized blocks very differently.
When the JVM executes a synchronized method, the executing thread identifies that the method's method_info structure has the ACC_SYNCHRONIZED flag set, then it automatically acquires the object's lock, calls the method, and releases the lock. If an exception occurs, the thread automatically releases the lock.
Synchronizing a method block, on the other hand, bypasses the JVM's built-in support for acquiring an object's lock and exception handling and requires that the functionality be explicitly written in byte code. If you read the byte code for a method with a synchronized block, you will see more than a dozen additional operations to manage this functionality.
This shows calls to generate both a synchronized method and a synchronized block:
The
synchronizedMethodGet()
method generates the following byte code:And here's the byte code from the
synchronizedBlockGet()
method:One significant difference between synchronized method and block is that, Synchronized block generally reduce scope of lock. As scope of lock is inversely proportional to performance, its always better to lock only critical section of code. One of the best example of using synchronized block is double checked locking in Singleton pattern where instead of locking whole
getInstance()
method we only lock critical section of code which is used to create Singleton instance. This improves performance drastically because locking is only required one or two times.While using synchronized methods, you will need to take extra care if you mix both static synchronized and non-static synchronized methods.
大多数情况下,我使用它来同步对列表或映射的访问,但我不想阻止对对象的所有方法的访问。
在下面的代码中,修改列表的线程不会阻塞等待正在修改映射的线程。 如果方法在对象上同步,则每个方法都必须等待,即使它们所做的修改不会发生冲突。
Most often I use this to synchronize access to a list or map but I don't want to block access to all methods of the object.
In the following code one thread modifying the list will not block waiting for a thread that is modifying the map. If the methods were synchronized on the object then each method would have to wait even though the modifications they are making would not conflict.
使用同步块,您可以拥有多个同步器,以便多个同时但不冲突的事情可以同时进行。
With synchronized blocks, you can have multiple synchronizers, so that multiple simultaneous but non-conflicting things can go on at the same time.
可以使用反射 API 检查同步方法。 这对于测试某些合约很有用,例如模型中的所有方法都是同步的。
以下代码片段打印了 Hashtable 的所有同步方法:
Synchronized methods can be checked using reflection API. This can be useful for testing some contracts, such as all methods in model are synchronized.
The following snippet prints all the synchronized methods of Hashtable:
使用同步块的重要注意事项:小心使用锁对象!
上面 user2277816 的代码片段说明了这一点,因为对字符串文字的引用被用作锁定对象。
意识到字符串文字在 Java 中是自动驻留的,您应该开始看到问题:在文字“锁”上同步的每一段代码都共享同一个锁! 这很容易导致完全不相关的代码片段出现死锁。
您需要小心的不仅仅是 String 对象。 装箱基元也是一种危险,因为自动装箱和 valueOf 方法可以重用相同的对象,具体取决于值。
欲了解更多信息,请参阅:
https:// /www.securecoding.cert.org/confluence/display/java/LCK01-J.+Do+not+synchronize+on+objects+that+may+be+reused
Important note on using the synchronized block: careful what you use as lock object!
The code snippet from user2277816 above illustrates this point in that a reference to a string literal is used as locking object.
Realize that string literals are automatically interned in Java and you should begin to see the problem: every piece of code that synchronizes on the literal "lock", shares the same lock! This can easily lead to deadlocks with completely unrelated pieces of code.
It is not just String objects that you need to be careful with. Boxed primitives are also a danger, since autoboxing and the valueOf methods can reuse the same objects, depending on the value.
For more information see:
https://www.securecoding.cert.org/confluence/display/java/LCK01-J.+Do+not+synchronize+on+objects+that+may+be+reused
通常在方法级别使用锁太粗鲁了。 为什么要通过锁定整个方法来锁定一段不访问任何共享资源的代码。 由于每个对象都有一个锁,因此您可以创建虚拟对象来实现块级同步。
块级别更有效,因为它不会锁定整个方法。
这里有一些示例
方法级别
块级别
[编辑]< /strong>
对于
Collection
,如Vector
和Hashtable
,它们在ArrayList
或HashMap
时同步> 不是,您需要设置同步关键字或调用集合同步方法:Often using a lock on a method level is too rude. Why lock up a piece of code that does not access any shared resources by locking up an entire method. Since each object has a lock, you can create dummy objects to implement block level synchronization.
The block level is more efficient because it does not lock the whole method.
Here some example
Method Level
Block Level
[Edit]
For
Collection
likeVector
andHashtable
they are synchronized whenArrayList
orHashMap
are not and you need set synchronized keyword or invoke Collections synchronized method:唯一的区别:与同步方法不同,同步块允许粒度锁定
基本上,
同步
块或方法已用于通过避免内存不一致来编写线程安全代码错误。这个问题很老了,在过去 7 年里很多事情都发生了变化。
为了线程安全引入了新的编程结构。
您可以通过使用高级并发 API 而不是
synchronied
块来实现线程安全。 本文档页面提供了良好的编程结构来实现线程安全。锁定对象 支持锁定惯用法,可简化许多并发应用程序。
执行器定义了一个高用于启动和管理线程的级别 API。 java.util.concurrent 提供的 Executor 实现提供了适合大型应用程序的线程池管理。
并发集合让一切变得更容易来管理大量数据集合,并且可以大大减少同步的需要。
原子变量具有以下功能:最大限度地减少同步并有助于避免内存一致性错误。
ThreadLocalRandom< /strong>(在 JDK 7 中)提供从多个线程高效生成伪随机数的功能。
同步的更好替代品是 ReentrantLock,使用
Lock
API带锁的示例:
请参阅 java.lang. util.concurrent 和 java.util.concurrent.atomic 也适用于其他编程结构。
也请参考此相关问题:
同步与锁定
The only difference : synchronized blocks allows granular locking unlike synchronized method
Basically
synchronized
block or methods have been used to write thread safe code by avoiding memory inconsistency errors.This question is very old and many things have been changed during last 7 years.
New programming constructs have been introduced for thread safety.
You can achieve thread safety by using advanced concurrency API instead of
synchronied
blocks. This documentation page provides good programming constructs to achieve thread safety.Lock Objects support locking idioms that simplify many concurrent applications.
Executors define a high-level API for launching and managing threads. Executor implementations provided by java.util.concurrent provide thread pool management suitable for large-scale applications.
Concurrent Collections make it easier to manage large collections of data, and can greatly reduce the need for synchronization.
Atomic Variables have features that minimize synchronization and help avoid memory consistency errors.
ThreadLocalRandom (in JDK 7) provides efficient generation of pseudorandom numbers from multiple threads.
Better replacement for synchronized is ReentrantLock, which uses
Lock
APIExample with locks:
Refer to java.util.concurrent and java.util.concurrent.atomic packages too for other programming constructs.
Refer to this related question too:
Synchronization vs Lock