https://www.geeksforgeeks.org/synchronized-in-java/
多线程程序可能经常遇到多线程试图访问相同资源并最终产生错误和无法预料的结果的情况。 因此需要通过某种同步方法确保只有一个线程可以在给定的时间点访问资源。 Java提供了一种使用synchronized块创建线程和同步其任务的方法。 Java中的同步块使用synchronized关键字标记。
Java中的同步块在某个对象上同步。在同一对象上同步的所有同步块一次只能在其中执行一个线程。尝试进入同步块的所有其他线程都被阻塞,直到同步块内的线程退出块。
以下是synchronized块的一般形式:
// Only one thread can execute at a time. // sync_object is a reference to an object // whose lock associates with the monitor. // The code is said to be synchronized on // the monitor object synchronized(sync_object) { // Access shared variables and other // shared resources }
此同步在Java中使用称为monitor的概念实现。在给定时间只有一个线程可以拥有monitor。当线程获得锁定时,就说它已进入monitor。尝试进入锁定monitor的所有其他线程将被挂起,直到第一个线程退出monitor。
以下是使用synchronized的多线程示例。
// A Java program to demonstrate working of
// synchronized.
import
java.io.*;
import
java.util.*;
// A Class used to send a message
class
Sender
{
public
void
send(String msg)
{
System.out.println("Sending\t"
+ msg );
try
{
Thread.sleep(1000);
}
catch
(Exception e)
{
System.out.println("Thread interrupted.");
}
System.out.println("\n"
+ msg + "Sent");
}
}
// Class for send a message using Threads
class
ThreadedSend extends
Thread
{
private
String msg;
private
Thread t;
Sender sender;
// Recieves a message object and a string
// message to be sent
ThreadedSend(String m, Sender obj)
{
msg = m;
sender = obj;
}
public
void
run()
{
// Only one thread can send a message
// at a time.
synchronized(sender)
{
// synchronizing the snd object
sender.send(msg);
}
}
}
// Driver class
class
SyncDemo
{
public
static
void
main(String args[])
{
Sender snd = new
Sender();
ThreadedSend S1 =
new
ThreadedSend( " Hi "
, snd );
ThreadedSend S2 =
new
ThreadedSend( " Bye "
, snd );
// Start two threads of ThreadedSend type
S1.start();
S2.start();
// wait for threads to end
try
{
S1.join();
S2.join();
}
catch(Exception e)
{
System.out.println("Interrupted");
}
}
}
Output: 每次我们运行都会产生相同的结果
Sending Hi Hi Sent Sending Bye Bye Sent
在上面的示例中,我们选择在ThreadedSend类的run()方法内同步Sender对象。或者,我们可以将整个send()块定义为synchronized,它将产生相同的结果。然后我们不必在ThreadedSend类中的run()方法内同步Message对象。
// An alternate implementation to demonstrate
// that we can use synchronized with method also.
class
Sender
{
public
synchronized
void
send(String msg)
{
System.out.println("Sending\t"
+ msg );
try
{
Thread.sleep(1000);
}
catch
(Exception e)
{
System.out.println("Thread interrupted.");
}
System.out.println("\n"
+ msg + "Sent");
}
}
我们并不总是需要同步整个方法。有时最好只同步方法的一部分。方法中的Java同步块使这成为可能。
// One more alternate implementation to demonstrate
// that synchronized can be used with only a part of
// method
class
Sender
{
public
void
send(String msg)
{
synchronized(this)
{
System.out.println("Sending\t"
+ msg );
try
{
Thread.sleep(1000);
}
catch
(Exception e)
{
System.out.println("Thread interrupted.");
}
System.out.println("\n"
+ msg + "Sent");
}
}
}