java 多个线程调用静态辅助方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6202939/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Multiple Threads calling static helper method
提问by MarioP
I have a web application running on Tomcat.
我有一个在 Tomcat 上运行的 Web 应用程序。
There are several calculations that need to be done on multiple places in the web application. Can I make those calculations static helper functions? If the server has enough processor cores, can multiple calls to that static function (resulting from multiple requests to different servlets) run parallel? Or does one request have to wait until the other request finished the call?
有几个计算需要在 Web 应用程序的多个地方完成。我可以使这些计算成为静态辅助函数吗?如果服务器有足够多的处理器内核,那么对该静态函数的多次调用(由对不同 servlet 的多次请求引起)能否并行运行?还是一个请求必须等到另一个请求完成呼叫?
public class Helper {
public static void doSomething(int arg1, int arg2) {
// do something with the args
return val;
}
}
if the calls run parallel: I have another helper class with static functions, but this class contains a private static member which is used in the static functions. How can I make sure that the functions are thread-safe?
如果调用并行运行:我有另一个带有静态函数的辅助类,但该类包含一个用于静态函数的私有静态成员。如何确保函数是线程安全的?
public class Helper {
private static SomeObject obj;
public static void changeMember() {
Helper.obj.changeValue();
}
public static String readMember() {
Helper.obj.readValue();
}
}
changeValue()
and readValue()
read/change the same member variable of Helper.obj
. Do I have to make the whole static functions synchronized, or just the block where Helper.obj
is used? If I should use a block, what object should I use to lock it?
changeValue()
并readValue()
读取/更改Helper.obj
. 我必须使整个静态函数同步,还是只需要使用块Helper.obj
?如果我应该使用一个块,我应该使用什么对象来锁定它?
采纳答案by Matt Ball
can i make those calculations static helper functions? if the server has enough processor cores, can multiple calls to that static function (resulting from multiple requests to different servlets) run parallel?
我可以让这些计算成为静态辅助函数吗?如果服务器有足够多的处理器内核,是否可以并行运行对该静态函数的多次调用(由对不同 servlet 的多个请求产生)?
Yes, and yes.
是的,是的。
do i have to make the whole static functions synchronized
我是否必须使整个静态函数同步
That will work.
那可行。
or just the block where
Helper.obj
is used
或只是块,其中
Helper.obj
使用
That will also work.
这也将起作用。
if i should use a block, what object should i use to lock it?
如果我应该使用一个块,我应该使用什么对象来锁定它?
Use a static Object
:
使用static Object
:
public class Helper {
private static SomeObject obj;
private static final Object mutex = new Object();
public static void changeMember() {
synchronized (mutex) {
obj.changeValue();
}
}
public static String readMember() {
synchronized (mutex) {
obj.readValue();
}
}
}
Ideally, though, you'd write the helper class to be immutable (stateless or otherwise) so that you just don't have to worry about thread safety.
不过,理想情况下,您应该将辅助类编写为不可变的(无状态或其他方式),这样您就不必担心线程安全。
回答by hvgotcodes
You should capture the calculations in a class, and create an instance of the class for each thread. What you have now is not threadsafe, as you are aware, and to make it threadsafe you will have to synchronize on the static resource/the methods that access that static resource, which will cause blocking.
您应该在一个类中捕获计算,并为每个线程创建该类的一个实例。正如您所知,您现在拥有的不是线程安全的,要使其成为线程安全的,您必须在静态资源/访问该静态资源的方法上进行同步,这将导致阻塞。
Note that there are patterns to help you with this. You can use the strategy pattern (in its canonical form, the strategy must be chosen at runtime, which might or might not apply here) or a variant. Just create a class for each calculation with an execute method (and an interface that has the method), and pass a context object to execute. The context holds all the state of the calculation. One strategy instance per thread, with its context, and you shouldn't have any issues.
请注意,有一些模式可以帮助您解决这个问题。您可以使用策略模式(在其规范形式中,必须在运行时选择策略,这可能适用也可能不适用)或变体。只需使用execute方法(以及具有该方法的接口)为每个计算创建一个类,并传递一个上下文对象来执行。上下文包含计算的所有状态。每个线程一个策略实例及其上下文,您不应该有任何问题。
回答by Peter Lawrey
If you don't have to share it you can make it thread local, then it doesn't have to be thread safe.
如果您不必共享它,您可以将其设为线程本地,那么它不必是线程安全的。
public class Helper {
private static final ThreadLocal<SomeObject> obj = new ThreadLocal<SomeObject>() {
public SomeObject initialValue() {
return enw SomeObject();
}
}
public static void changeMember() {
Helper.obj.get().changeValue();
}
public static String readMember() {
Helper.obj.get().readValue();
}
}
回答by Tomasz Stanczak
I'll sum up here what has been said in the comments to the Matt Ball's answer, since it got pretty long at the end and the message gets lost: and the message was
我将在这里总结一下对 Matt Ball 的回答的评论中所说的内容,因为它最后很长并且信息丢失了:并且信息是
in a shared environment like a web/application server you should try very hard to find a solution without synchronizing. Using static helpers synchronized on static object might work well enough for stand alone application with a single user in front of the screen, in a multiuser/multiapplication scenario doing this would most probably end in a very poor performance - it would effectively mean serializing access to your application, all users would have to wait on the same lock. You might not notice the problem for a long time: if the calculation are fast enough and load is evenly distributed.
在像 Web/应用程序服务器这样的共享环境中,您应该非常努力地寻找不同步的解决方案。使用在静态对象上同步的静态助手对于屏幕前只有一个用户的独立应用程序来说可能工作得很好,在多用户/多应用程序场景中,这样做很可能会导致非常差的性能——这实际上意味着序列化访问您的应用程序,所有用户都必须等待同一个锁。您可能在很长一段时间内都不会注意到这个问题:如果计算速度足够快并且负载分布均匀。
But then all of a sudden all your users might try to go through the calculation at 9am and you app will stop to work! I mean not really stop, but they all would block on the lock and make a huge queue.
但是突然之间,您的所有用户可能会尝试在上午 9 点进行计算,而您的应用程序将停止工作!我的意思是没有真正停止,但它们都会阻塞锁并排成一个巨大的队列。
Now regardless the necessity of a shared state, since you originally named calculations as subject of synchronization: do their results need to be shared? Or are those calculations specific to a user/session? In the latter case a ThreadLocal as per Peter Lawrey would be enough. Otherwise I'd say for overall performance it would be better to duplicate the calculations for everybody needing them in order not to synchronize (depends on the cost).
现在不管共享状态的必要性,因为您最初将计算命名为同步的主题:它们的结果是否需要共享?或者那些计算特定于用户/会话?在后一种情况下,按照 Peter Lawrey 的 ThreadLocal 就足够了。否则我会说为了整体性能最好为每个需要它们的人复制计算以免同步(取决于成本)。
Session management should also be better left to the container: it has been optimized to handle them efficiently, if necessary including clustering etc. I doubt one could make better solution without investing lot of work and making lots of bugs on the way there. But as Matt Ball has stated it should be better asked separately.
会话管理也应该更好地留给容器:它已经过优化以有效地处理它们,如有必要,包括集群等。我怀疑有人可以在不投入大量工作并在途中产生大量错误的情况下做出更好的解决方案。但正如马特鲍尔所说,最好单独询问。
回答by Spektr
In the first case you don't have to worry about threading issues, because the variables are local to each thread. You correctly identify the problem in the second case, though, because multiple threads will be reading/writing the same object. Synchronizing on the methods will work, as would synchronized blocks.
在第一种情况下,您不必担心线程问题,因为变量对于每个线程都是本地的。但是,您在第二种情况下正确识别了问题,因为多个线程将读取/写入同一个对象。同步方法将起作用,就像同步块一样。
回答by Fabian Barney
For the first part: Yes, these calls are independent and run in parallel when called by different threads.
对于第一部分:是的,这些调用是独立的,并且在被不同线程调用时并行运行。
For the last part: Use synchronize blocks on the concurrent object, a dummy object or class object. Be aware of cascaded synchronize blocks. They can lead into dead locks when acquired in different order.
最后一部分:在并发对象、虚拟对象或类对象上使用同步块。请注意级联同步块。当以不同的顺序获取时,它们可能导致死锁。
回答by Karl-Bj?rnar ?ie
If you are worried about synchronization and thread safety, don't use static helpers. Create a normal class with your helper methods and create an instance upon servlet request. Keep it simple :-)
如果您担心同步和线程安全,请不要使用静态助手。使用您的辅助方法创建一个普通类,并根据 servlet 请求创建一个实例。把事情简单化 :-)