多线程调用静态辅助方法

发布于 2024-11-12 06:18:35 字数 831 浏览 4 评论 0原文

我有一个在 Tomcat 上运行的 Web 应用程序。

有一些计算需要在 Web 应用程序中的多个位置进行。我可以使这些计算成为静态辅助函数吗?如果服务器有足够的处理器核心,是否可以并行运行对该静态函数的多个调用(由于对不同 servlet 的多个请求而产生)?或者一个请求是否必须等待另一个请求完成调用?

public class Helper {
    public static void doSomething(int arg1, int arg2) {
        // do something with the args
        return val;
    }
}

如果调用并行运行: 我有另一个带有静态函数的辅助类,但该类包含一个在静态函数中使用的私有静态成员。如何确保函数是线程安全的?

public class Helper {

    private static SomeObject obj;

    public static void changeMember() {
        Helper.obj.changeValue();
    }

    public static String readMember() {
        Helper.obj.readValue();
    }

}

changeValue()readValue() 读取/更改 Helper.obj 的相同成员变量。我是否必须同步整个静态函数,或者仅同步使用 Helper.obj 的块?如果我应该使用块,我应该使用什么对象来锁定它?

I have a web application running on Tomcat.

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?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

失退 2024-11-19 06:18:35

我可以使这些计算成为静态辅助函数吗?如果服务器有足够的处理器核心,是否可以并行运行对该静态函数的多个调用(由于对不同 servlet 的多个请求而产生)?

是的,是的。

我是否必须使整个静态函数同步

这样才能工作。

或者只是使用 Helper.obj 的块

也可以。

如果我应该使用块,我应该使用什么对象来锁定它?

使用静态对象:

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();
        }
    }
}

不过,理想情况下,您应该将辅助类编写为不可变的(无状态或其他),这样您就不必担心线程安全。

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?

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

That will also work.

if i should use a block, what object should i use to lock it?

Use a 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.

聽兲甴掵 2024-11-19 06:18:35

您应该捕获类中的计算,并为每个线程创建该类的实例。正如您所知,您现在所拥有的不是线程安全的,为了使其线程安全,您必须在静态资源/访问该静态资源的方法上进行同步,这将导致阻塞。

请注意,有一些模式可以帮助您完成此操作。您可以使用策略模式(在其规范形式中,必须在运行时选择策略,这可能适用也可能不适用)或变体。只需使用执行方法(以及具有该方法的接口)为每个计算创建一个类,并传递一个上下文对象来执行。上下文保存了所有计算的状态。每个线程一个策略实例及其上下文,您不应该遇到任何问题。

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.

零崎曲识 2024-11-19 06:18:35

如果您不必共享它,您可以将其设置为本地线程,那么它不必是线程安全的。

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();
}

}

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();
}

}
伊面 2024-11-19 06:18:35

我将在这里总结一下马特·鲍尔的答案的评论中所说的内容,因为它最后很长并且消息丢失了:并且该消息位于

共享环境中,例如您应该尝试的网络/应用程序服务器很难找到不同步的解决方案。使用在静态对象上同步的静态帮助器对于屏幕前有单个用户的独立应用程序来说可能足够工作,在多用户/多应用程序场景中,这样做很可能会导致性能非常差 - 这实际上意味着序列化对在您的应用程序中,所有用户都必须等待同一个锁。您可能很长一段时间都不会注意到这个问题:如果计算足够快并且负载分布均匀。

但突然间,您的所有用户可能会尝试在上午 9 点进行计算,而您的应用程序将停止工作!我的意思是不是真的停止,但它们都会阻塞在锁上并排成一个巨大的队列。

现在,无论共享状态的必要性如何,因为您最初将计算命名为同步主题:它们的结果是否需要共享?或者这些计算是否特定于用户/会话?在后一种情况下,按照 Peter Lawrey 的说法,ThreadLocal 就足够了。否则,我想说,为了整体性能,最好为每个需要它们的人重复计算,以免同步(取决于成本)。

会话管理也应该更好地留给容器:它已经过优化,可以有效地处理它们,如果有必要,包括集群等。我怀疑是否可以在不投入大量工作并在此过程中产生大量错误的情况下制定更好的解决方案。但正如马特·鲍尔所说,最好单独询问。

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

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.

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.

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).

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.

再浓的妆也掩不了殇 2024-11-19 06:18:35

在第一种情况下,您不必担心线程问题,因为变量对于每个线程来说都是本地的。不过,您可以正确地识别第二种情况下的问题,因为多个线程将读取/写入同一对象。方法上的同步将起作用,就像同步块一样。

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.

渡你暖光 2024-11-19 06:18:35

对于第一部分:
是的,这些调用是独立的,并且在被不同线程调用时并行运行。

对于最后一部分:
在并发对象、虚拟对象或类对象上使用同步块。注意级联同步块。当以不同的顺序获取它们时,它们可能会导致死锁。

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.

柠北森屋 2024-11-19 06:18:35

如果您担心同步和线程安全,请不要使用静态助手。使用辅助方法创建一个普通类,并根据 servlet 请求创建一个实例。保持简单:-)

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 :-)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文