【问题标题】:How to lock two variables written by threadA and read by threadB (Android)如何锁定由threadS写入并由线程读取的两个变量(Android)
【发布时间】:2012-05-02 22:02:56
【问题描述】:

我正在开发一个使用两个线程的 Android 应用程序,第一个(写入器)线程正在更新两个变量,第二个(读取器)线程在计算中使用这两个变量。
如何确保第二个线程接收到正确的值?
这是我的第一个 java 锁定问题。我一直在阅读有关同步、易失性、trylock 的信息,但仍不清楚。对于一个变量,这很“容易”,但不明白如何对两个变量执行此操作。

详情:
这些变量在一个共享的公共类 AppState extends Application 中:

public long appstate.writerVar1;
public int appstate.writerVar2;

在主活动中创建线程并将应用状态传递给线程:

writerThread.appstate = appstate;
...
readerThread.appstate = appstate;

然后可以通过 writerThread 和 readerThread 访问变量,如下所示:

writerThread,示例:

appstate.writerVar1 = 1234;
appstate.writerVar2 = 5678;

readerThread,例如:

if( (appstate.writerVar1 == 9) && (appstate.writerVar2 == 6) ){

它应该像这样工作:

作家线程:
- 锁定两个变量
- 使用新值更新两者
- 解锁

读者话题:
- 锁定两个变量
- 读取值
- 解锁

有人可以向我展示执行此操作的 java 代码吗?谢谢!

--- 添加于 2012 年 4 月 23 日 ---

谢谢。抱歉延迟回答,但请阅读有关此内容的更多信息,包括有关可变对象的信息,http://www.javaranch.com/journal/2003/04/immutable.htm
我试图了解如何从在主活动中创建的 writerThread 和 readerThread 调用它,并想出了以下代码:

writerThread:

私人 WriterState wSW;
...
var1W = 123;
var2W = 456;
wSW = new WriterState(var1W, var2W);
appstate.setWriterState(wsW);

readerThread:


私人 WriterState wsR;
...
wsR = appstate.getWriterState();
var1R = wsR.getVar1();
var2R = wsR.getVar2();

我尝试了这段代码,它似乎运行正常。我可以在读取 var1R 和 var2R 之间添加一个新的 var1W 和 var2W。

现在我的下一个问题:
a) 这个代码可以吗?
b) 假设 setWriterState 代码在一个循环中,这不会吃掉所有的内存吗?
c) WriterState 类怎么可能是可变的,我相信这里不可能是这样(你说:如果 WriterState 类是可变的)

我还在这里看到了一个例子 http://tutorials.jenkov.com/java-concurrency/synchronized.html 。 他们将 Counter 对象传递给两个线程。在这种情况下,这样的事情是不可能的吗?

【问题讨论】:

    标签: java android multithreading locking


    【解决方案1】:

    synchronizedjava.util.concurrent.Lock 的编程使用都可以,但我更喜欢第二个。假设读者线程只需要对值进行简单检查,这里有一个解决方案:

    编辑:这样阅读器线程不会读取变量。相反,读者感兴趣的检查是在 AppState 类中完成的。显然,这仅在您只需要检查两个变量的单一事物时才有效,并且是事先知道的。

    public class AppState
    {
        private long writerVar1;
        private int writerVar2;
    
        private ReentrantLock lock = new ReentrantLock();
    
        public void setValues(long longValue, int intValue)
        {
            lock.lock();
            try
            {
                writerVar1 = longValue;
                writerVar2 = intValue;
            }
            finally
            {
                lock.unlock();
            }
        }
    
        public boolean isValuesCorrect()
        {
            lock.lock();
            try
            {
                return (writerVar1 == 9) && (writerVar2 == 6);
            }
            finally
            {
                lock.unlock();
            }
        }
    //rest of the class body goes here
    }
    

    请注意,两个值必须private,并且只能由使用相同锁的方法访问,否则您实际上没有线程安全访问权限。

    【讨论】:

    • 这不是一个解决方案,因为阅读器线程需要分别获取这两个值
    【解决方案2】:

    OO 设计的关键是封装。而在处理多个线程时,它变得更加重要。如果这两个变量构成必须更新和连贯读取的共享状态,那么

    • 此共享状态不应公开,因为它强制此状态的每个客户端都尊重与其他客户端的协作协议
    • 此共享状态应封装在一个对象中,该对象控制对状态的访问

    因此,AppState 对象的字段应该是私有的。这条规则在 99% 的情况下都是正确的。公共领域是一个很大的禁忌。

    然后对字段的所有访问都应该同步(读取和写入)。由于这两个字段构成了一条连贯的信息,因此您应该将它们放在一个类中(我们称之为 WriterState)。如果这个类是可变的,那么每次调用 getState() 和 setState() 时都必须通过共享状态来复制一份,所以使用不可变的类更容易,更快捷,可以被多个共享没有同步的线程。

    /**
     * Immutable class: final, contains only final fields wich are themselves immutable.
     */
    public final class WriterState {
        private final long var1;
        private final int var2;
    
        public WriterState(long var1, int var2) {
            this.var1 = var1;
            this.var2 = var2;
        }
    
        public long getVar1() {
            return this.var1;
        }
    
        public int getVar2() {
            return this.var2;
        }
    }
    
    public class AppState {
        private WriterState writerState;
    
        public synchronized void setWriterState(WriterState ws) {
            this.writerState = ws;
        }
    
        public synchronized WriterState getWriterState() {
            return this.writerState;
        }
    }
    

    如果 WriterState 类是可变的,您应该执行以下操作以使其成为线程安全的:

    public class AppState {
        private WriterState writerState;
    
        public synchronized void setWriterState(WriterState ws) {
            this.writerStatenew WriterState(ws.getVar1(), ws.getVar2());
        }
    
        public synchronized WriterState getWriterState() {
            return new WriterState(this.writerState.getVar1(), this.writerState.getVar2());
        }
    }
    

    【讨论】:

    • 感谢您对延迟的回答感到抱歉,但必须阅读更多关于您所写内容的信息...我在上面添加了新信息,请参阅 --- 2012 年 4 月 23 日添加 --- 我的下一个问题: a) 这个代码可以吗? b) 假设 setWriterState 代码在一个循环中,这不会吃掉所有的内存吗? c) WriterState 类怎么可能是可变的,我相信这里不可能是这样(你说:如果 WriterState 类是可变的)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多