Я написал несколько многопоточных хобби-программ и некоторые из них в своих предыдущих (инженерных / физических) исследованиях, так что я считаю, что у меня есть начальные знания в области синхронизации / безопасности потоков и примитивов, чтосреднестатистический пользователь обнаруживает, что связывается с 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();
}
}
Это просто мой собственный эксперименттак что он не закончен каким-либо образом, но у меня есть один достойный проект, использующий его прямо сейчас, и он действительно очень помогает.