我正在研究 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/