Java: платформа для общих потоков данных - PullRequest
3 голосов
/ 24 августа 2011

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

То, что мне нужно, и не существует надлежащего метода маркировки экземпляров или статических членов классов как общих для разных потоков.Подумайте об этом, у нас есть правила доступа, такие как private / protected / public и соглашения о том, как называть геттеры / сеттеры, и многое другое.

Но как насчет потоков?Что делать, если я хочу пометить переменную как общую для потока и выполнить ее по определенным правилам?Volatile / Atomic refs могут делать эту работу, но иногда вам просто нужно использовать мьютексы.И когда вам придется вручную забыть использовать что-то ... вы забудете об этом :) - В какой-то момент.

Итак, у меня возникла идея, и я вижу, что я не первый, я тоже проверилhttp://checkthread.org/example-threadsafe.html - Кажется, у них довольно приличный анализатор кода, который я мог бы попробовать позже, что позволяет мне делать некоторые вещи, которые я хочу.

Но вернемся к первоначальной проблеме.Скажем, нам нужно что-то немного более низкое, чем структура передачи сообщений, и нам нужно что-то немного более высокое, чем примитивные мьютексы ... Что у нас есть ... ну ... ничего?

Итак, по сути, я создал своего рода супер-простой фреймворк Java для потоков, который позволяет объявлять членов класса как общие или не общие ... ну вроде:).

Ниже приведен пример того, как его можно использовать:

public class SimClient extends AbstractLooper {

    private static final int DEFAULT_HEARTBEAT_TIMEOUT_MILLIS = 2000;
    // Accessed by single threads only
    private final SocketAddress socketAddress;
    private final Parser parser;
    private final Callback cb;
    private final Heart heart;
    private boolean lookingForFirstMsg = true;
    private BufferedInputStream is;
    // May be accessed by several threads (T*)  
    private final Shared<AllThreadsVars> shared = new Shared<>(new AllThreadsVars());

.
.
.
.

    static class AllThreadsVars {

        public boolean connected = false;
        public Socket socket = new Socket();
        public BufferedOutputStream os = null;
        public long lastMessageAt = 0;
    }

И для доступа к переменным, помеченным как общий поток, вы должны отправить функтор, похожий на runnable, в общий объект:

public final void transmit(final byte[] data) {
    shared.run(new SharedRunnable<AllThreadsVars, Object, Object>() {

        @Override
        public Object run(final AllThreadsVars sharedVariable, final Object input) {
            try {
                if (sharedVariable.socket.isConnected() && sharedVariable.os != null) {
                    sharedVariable.os.write(data);
                    sharedVariable.os.flush();
                }
            } catch (final Exception e) { // Disconnected
                setLastMessageAt(0);
            }
            return null;
        }
    }, null);
}

Где общий исполняемый объект определяется как:

public interface SharedRunnable<SHARED_TYPE, INPUT, OUTPUT> {
    OUTPUT run(final SHARED_TYPE s, final INPUT input);
}

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

По сути, это чрезвычайно полезно для меня, и мне интересно, могу ли я просто заново изобрести колесо или это может быть неким антипаттерном, о котором я не знаю.И я действительно не знаю, кого спросить.(О да, и Shared .run ( SharedRunnable r, INPUT input) работает так же, как

private final <OUTPUT, INPUT> OUTPUT run(final SharedRunnable<SHARED_TYPE, INPUT, OUTPUT> r, final INPUT input) { 
    try {
        lock.lock();
        return r.run(sharedVariable, input);
    } finally {
        lock.unlock();
    }
}

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

Ответы [ 2 ]

4 голосов
/ 24 августа 2011

Вы имеете в виду что-то вроде этого ? (который может быть реализован с помощью таких инструментов, как findbugs .)

0 голосов
/ 25 августа 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...