多线程程序经常会遇到一种问题,就是当多个线程试图访问同一个资源的时候,最后会产生不可预料的结果。因此,需要使用一些同步的措施来保证在一个给定的时间点只有一个线程可以来访问这个资源。
Java提供了一种使用synchronized块创建线程和同步其任务的方法。 Java中的同步块使用synchronized关键字标记。 Java中的同步块在某个对象上同步。 在同一对象上同步的所有同步块一次只能在其中执行一个线程。 尝试进入同步块的所有其他线程都被阻塞,直到同步块内的线程退出块。
以下是同步块的一般形式:
//一次只能执行一个线程。sync_object是对象的引用,其锁定与监视器关联。代码被称为同步,监视器对象
synchronized(sync_object){
// Access shared variables and other
// shared resources
}
此同步在Java中使用称为监视器的概念实现。 在给定时间只有一个线程可以拥有监视器。 当线程获得锁定时,据说它已进入监视器。 尝试进入锁定监视器的所有其他线程将被挂起,直到第一个线程退出监视器。
import java.io.*;
import java.util.*;
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 ThreadedSend extends Thread {
private String msg;
private Thread t;
Sender sender;
ThreadedSend(String m, Sender obj) {
msg = m;
sender = obj;
}
public void run() {
**synchronized(sender)** {
sender.send(msg);
}
}
}
class SyncDemo {
public static void main(String args[])
{
Sender snd = new Sender();
ThreadedSend S1 =
new ThreadedSend( " Hi " , snd );
ThreadedSend S2 =
new ThreadedSend( " Bye " , snd );
S1.start();
S2.start();
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,它将产生相同的结果。 然后我们不必在ThreadedSend类中的run()方法内同步Message对象
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同步块使这成为可能。
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");
}
}
}