如何同步或lockingJava中的variables?

让我使用这个小而简单的示例:

class Sample { private String msg = null; public void newmsg(String x){ msg = x; } public String getmsg(){ String temp = msg; msg = null; return temp; } } 

假设函数newmsg()被其他我无权访问的线程调用。

我想使用synchonize方法来保证每次只有一个函数使用msgstring。 换句话说,函数newmsg()不能和getmsg()同时运行。

这很简单:

 class Sample { private String message = null; private final Object lock = new Object(); public void newMessage(String x) { synchronized (lock) { message = x; } } public String getMessage() { synchronized (lock) { String temp = message; message = null; return temp; } } } 

请注意,我没有让方法本身同步或在this同步。 我坚信,只有在你的代码可以访问的对象上才能获取locking是个好主意,除非你故意暴露locking。 这使得更容易让自己放心,没有别的东西会以不同的顺序获取锁,等等。

对于这个function,你最好不要使用锁。 试试AtomicReference。

 public class Sample { private final AtomicReference<String> msg = new AtomicReference<String>(); public void setMsg(String x) { msg.set(x); } public String getMsg() { return msg.getAndSet(null); } } 

没有锁需要和代码更简单恕我直言。 无论如何,它使用一个标准的构造,它可以做你想做的事情。

在这个简单的例子中,你可以把两个方法签名中的public方法synchronized为一个修饰符。

更复杂的场景需要其他的东西。

从Java 1.5开始,考虑java.util.concurrent包总是一个好主意。 它们是目前在java中最先进的locking机制。 同步机制比java.util.concurrent类更重要。

这个例子看起来像这样:

 import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Sample { private final Lock lock = new ReentrantLock(); private String message = null; public void newmsg(String msg) { try { lock.lock(); message = msg; } finally { lock.unlock(); } } public String getmsg() { try { lock.lock(); String temp = message; message = null; return temp; } finally { lock.unlock(); } } } 

使用synchronized关键字。

 class sample { private String msg=null; public synchronized void newmsg(String x){ msg=x; } public synchronized string getmsg(){ String temp=msg; msg=null; return msg; } } 

对方法使用synchronized关键字将要求线程获取sample实例的locking。 因此,如果任何一个线程在newmsg() ,那么即使它试图调用getmsg() ,其他线程也不能获得sample实例的locking。

另一方面,如果你的方法执行长时间运行的操作,那么使用synchronized方法可能会成为一个瓶颈 – 所有的线程,即使他们想要调用可能交错的对象中的其他方法,仍然需要等待。

国际海事组织,在你的简单的例子,可以使用同步的方法,因为你实际上有两个不应该交错的方法。 然而,在不同情况下,如Joh Skeet的回答所示,locking对象可能会更有意义。

如果在另一个场合,你正在同步一个集合,而不是一个string,也许你正在迭代集合,并担心它变异,Java 5提供:

  • CopyOnWriteArrayList
  • CopyOnWriteArraySet