Подтвердить что ты не робот

Как обеспечить безопасность потока утилитарного статического метода?

Есть ли какой-либо общий способ или правила, с помощью которых мы можем обеспечить безопасность потоков статических методов, специально используемых в различных классах полезности любых приложений. Здесь я хочу конкретно указать безопасность потоков веб-приложений.

Хорошо известно, что статические методы с неизменяемыми объектами в качестве параметров являются потокобезопасными, а Mutable Objects - нет.

Если у меня есть метод утилиты для некоторой обработки java.util.Date, и этот метод принимает экземпляр java.util.Date, тогда этот метод не будет потокобезопасным. Тогда как сделать его потокобезопасным без изменения способа передачи параметров?

public class DateUtils {

    public static Date getNormalizeDate(Date date) {
        // some operations
    }   
}

Также является ли класс javax.faces.context.FacesContext изменчивым? Является ли потокобезопасным передать экземпляр этого класса в такой статический метод утилиты?

Этот список классов, экземпляры которых могут быть или не могут быть переданы как параметры, может быть длинным; поэтому какие моменты мы должны иметь в виду при написании кодов таких классов полезности?

4b9b3361

Ответ 1

Хорошо известно, что статические методы с неизменяемыми объектами в качестве параметров являются потокобезопасными и изменяемыми объектами.

Я бы оспорил это. Аргументы, переданные методу, хранятся в стеке, что является идиомой для каждой нити.

Если ваш параметр является изменяемым объектом, таким как Date, тогда вам нужно обеспечить, чтобы другие потоки не изменяли его одновременно в другом месте. Но это другое дело, не связанное с безопасностью потока вашего метода.

Метод, который вы опубликовали, является потокобезопасным. Он не поддерживает состояние и действует только по его аргументам.

Я настоятельно рекомендую вам прочитать Java Concurrency на практике или аналогичную книгу, посвященную безопасности потоков на Java. Это сложный вопрос, который не может быть рассмотрен надлежащим образом через несколько ответов StackOverflow.

Ответ 2

Так как ваш класс не содержит переменных-членов, ваш метод не имеет состояния (он использует только локальные переменные и аргумент) и поэтому является потокобезопасным.

Код, который его вызывает, может быть небезопасным, но это другое обсуждение. Например, дата не является потокобезопасной, если вызывающий код считывает дату, написанную другим потоком, вы должны использовать правильную синхронизацию в коде записи и чтения даты.

Ответ 3

Учитывая структуру JVM, локальные переменные, параметры метода и возвращаемые значения по своей природе являются "поточно-ориентированными". Но переменные экземпляра и переменные класса будут поточно-ориентированными, только если вы спроектируете свой класс соответствующим образом. больше здесь

Ответ 4

Я бы рекомендовал создать копию этого (изменяемого) объекта, как только начнется метод, и использовать копию вместо исходного параметра.

Что-то вроде этого

public static Date getNormalizeDate(Date date) {
    Date input = new Date(date.getTime());
    // ...
}

Ответ 5

Вот как я об этом думаю: представьте себе CampSite (это статический метод). Как турист, я могу принести кучу объектов в свой рюкзак (чтобы аргументы передавались в стек). CampSite предоставляет мне место для размещения моей палатки, моей походной плиты и т.д., Но если единственное, что делает CampSite, это позволяет мне изменять свои собственные объекты, то он безопасен для потоков. CampSite может даже создавать вещи из воздуха (FirePit firepit = new FirePit();), которые также создаются в стеке.

В любое время я могу исчезнуть со всеми моими предметами в моей стойке, и может появиться один из любых других отдыхающих, которые будут делать то же, что и в прошлый раз, когда исчезли. Различные потоки в этом CampSite не будут иметь доступа к объектам в стеке, созданному CampSite в других потоках.

Скажем, там только один campStove (один объект CampStove, а не отдельные экземпляры). Если по какой-то причине я разделяю объект CampStove, то существуют соображения о многопоточности. Я не хочу включать мой campStove, исчезать, а затем снова появляться после того, как какой-то другой турист отключил его - я бы всегда проверял, был ли мой хот-дог готов, и никогда не будет. Вы должны были бы поместить некоторую синхронизацию где-нибудь... в классе CampStove, в методе, который вызывал CampSite, или в самом CampSite... но, как говорит Дункан Джонс, "это другое дело".

Обратите внимание, что даже если бы мы размещались в отдельных экземплярах нестатических объектов CampSite, совместное использование campStove имело бы те же соображения о многопоточности.

Ответ 6

Я вижу много ответов, но ни один из них не указывает на причину.

Так что это можно представить так: всякий раз, когда создается поток, он создается со своим собственным стеком (я предполагаю, что размер стека на момент создания составляет ~ 2 МБ). Таким образом, любое выполнение, которое происходит, на самом деле происходит в контексте этого стека потоков. Любая созданная переменная живет в куче, но ссылается на нее в стеке, за исключением того, что статические переменные не находятся в стеке потока.

Любой вызов функции фактически помещается в стек потоков, будь то статический или нестатический. Поскольку полный метод был помещен в стек, любое создание переменной происходит в стеке (опять же, за исключением статических переменных) и доступно только одному потоку.

Таким образом, все методы являются потокобезопасными, пока они не изменят состояние некоторой статической переменной.