如何同步或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方法来保证每次只有一个函数使用msg
string。 换句话说,函数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