多线程程序可能经常遇到多个线程尝试访问相同资源并最终产生错误和无法预料的结果的情况。
因此需要通过某种同步方法确保在给定时间点只有一个线程可以访问资源。Java 提供了一种使用同步块创建线程和同步它们的任务的方法。Java 中的同步块用 synchronized 关键字标记。Java 中的同步块在某个对象上同步。在同一个对象上同步的所有同步块一次只能在其中执行一个线程。所有其他试图进入同步块的线程都被阻塞,直到同步块内的线程退出该块。
synchronized(sync_object)
{
// Access shared variables and other
// shared resources
}
这种同步是在 Java 中通过一个称为监视器的概念实现的。在给定时间只有一个线程可以拥有一个监视器。当一个线程获得一个锁时,就说它已经进入了监视器。所有其他试图进入锁定监视器的线程都将被挂起,直到第一个线程退出监视器。
以下是带同步的多线程示例。
// 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;
Sender sender;
// Receives 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 send object
sender.send(msg);
}
}
}
// Driver class
class SyncDemo
{
public static void main(String args[])
{
Sender send = new Sender();
ThreadedSend S1 =
new ThreadedSend( " Hi " , send );
ThreadedSend S2 =
new ThreadedSend( " Bye " , send );
// 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");
}
}
}
输出:
Sending Hi
Hi Sent
Sending Bye
Bye Sent
在上面的例子中,我们选择在 ThreadedSend 类的 run() 方法中同步 Sender 对象。或者,我们可以将整个 send() 块定义为 synchronized, 产生相同的结果。代码如下:
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");
}
}