Java:线程共享数据的框架

时间:2011-08-24 17:34:55

标签: java multithreading thread-safety

我已经编写了一些多线程的业余爱好程序,还有一些在我以前的(工程/物理)研究中,所以我认为自己在同步/线程安全和原语方面有一个高于初学者的知识,是什么普通用户发现要与JMM和多线程等进行挑战。

我发现我需要并且没有正确的方法来标记不同线程共享的实例或类的静态成员。考虑一下,我们有访问规则,例如private / protected / public以及如何命名getter / setter和许多事情的约定。

但线程怎么样?如果我想将变量标记为共享线程并使其遵循某些规则,该怎么办? 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;
    }

要访问标记为线程共享的变量,您必须向Shared对象发送类似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);
}

共享runnable的定义如下:

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

这是怎么回事? 好吧,这给了我帮助(是的,你可以泄漏并打破它,但不太可能)我可以将变量集(不仅仅是变量)标记为线程共享,一旦完成,在编译时保证它(我不能忘记同步某些方法)。它还允许我标准化并执行测试以在编译时查找可能的死锁(虽然atm我只在运行时实现它,因为在编译时使用上面的框架执行它可能需要的不仅仅是java编译器)。

基本上这对我来说非常有用,我想知道我是否只是在这里重新发明轮子,或者这可能是一些我不知道的反模式。我真的不知道该问谁。 (哦是的和共享 .run( SharedRunnable r, 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 个答案:

答案 0 :(得分:4)

你的意思是this? (可以使用findbugs等工具强制执行。)

答案 1 :(得分:0)

如果您有值应该共享,那么最好的方法是将其封装在类中。这样调用者确实需要知道您正在使用的线程模型。如果你想知道内部使用什么模型,你可以读取源代码,但调用者不能忘记正确访问ConcurrentMap(例如),因为它的所有方法都是线程安全的。