java - 使用锁对象来同步我的成员变量

标签 java multithreading

我正在研究 Java 中的一个更高级的主题,即多线程主题。

我看到很多代码使用单独的对象锁Object lock = new Object();来同步某些类数据成员。

package multithreading;

import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

class ProduceConsume {

    private LinkedList<Integer> queue = new LinkedList<>();
    private final int LIMIT = 10;
    private final Object lock = new Object();

    public void produce() throws InterruptedException {
        int value = 0;

        while (true) {

            synchronized (lock) {
                while (queue.size() == LIMIT) {
                    lock.wait();
                }

                queue.add(value++);
                lock.notify();
            }
        }
    }

    public void consume() throws InterruptedException {
        while (true) {
            Thread.sleep(1000);

            synchronized (lock) {
                while (queue.size() == 0) {
                    lock.wait();
                }

                System.out.print("Size is: " + queue.size());
                int value = queue.removeFirst();
                System.out.println("; value is: " + value);

                lock.notify();
            }
        }
    }

}


public class ProducerConsumerWaitNotify {

    public static void main(String[] args) throws InterruptedException {

        ProduceConsume object = new ProduceConsume();

        ExecutorService execuor = Executors.newFixedThreadPool(2);

        execuor.submit(new Runnable() {

            @Override
            public void run() {
                try {
                    object.produce();
                } catch (InterruptedException ex) {
                    Logger.getLogger(ProducerConsumerWaitNotify.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
        execuor.submit(new Runnable() {

            @Override
            public void run() {
                try {
                    object.consume();
                } catch (InterruptedException ex) {
                    Logger.getLogger(ProducerConsumerWaitNotify.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });

        execuor.shutdown();
        execuor.awaitTermination(1000, TimeUnit.DAYS);
    }
}

为什么我们不应该锁定 LinkedList 对象本身?这不是我看到的使用这种技术的唯一例子。这是一个好的做法吗?

但是我觉得如果我有两个单独的类用于生产和消费,并且它将链表作为其构造函数的成员,那么我必须在此链表对象上进行同步,对吗?

我知道 concurrent 包中的类是线程安全的,但这不是我的问题,我是在询问上述两种方法之间的最佳实践?

最佳答案

你可以,因为它是你类(class)的私有(private)成员,只有你可以锁定它。如果你管理得好,那么用户就不会仅仅通过使用你的类的实例来导致死锁。如果该字段是公共(public)的,那么用户可以对其加锁,那么如果您在类内使用相同的字段进行同步,则可能会出现死锁。这就是为什么我们也不在 this 指针上加锁。

但是,使用单个对象进行锁定有几个原因:

您可以将对象命名为 controlLockerObject(用于序列化公共(public)访问)、listLockerObject(用于序列化对列表的访问)、updateLockerObject(用于序列化对用于更新某些内容的代码区域的访问)等。

您可以将对象声明为final,这样就不会意外替换或删除用于同步的对象。

关于java - 使用锁对象来同步我的成员变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36217361/

相关文章:

java - Firebase onDisconnect() 不工作

java - 如何用不同的方法绘制 Sprite libgdx

java - Google 应用引擎的 gradle 单元测试在哪里期望 persistence.xml?

java - 从非 UI 线程调用 Snackbar.make() 是如何工作的?

javascript - 在接收推送通知的同时在后台运行 javascript 函数?

c# - 秒表与 Task.Wait

java - EAD xsd 生成的 JAXBException

java - 使用 Spring 应用程序将 Liquibase 嵌入到 jar 中

c# - 使 MTA 中的锁定更容易

ios - Swift:运行时:线程问题:MyApp.DownloadManager.progress.setter 中的数据竞争:Swift.Float at 0x7b1400209130