Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在java.util.concurrent.Locks中使用API时,到底锁定了什么?_Java_Multithreading - Fatal编程技术网

在java.util.concurrent.Locks中使用API时,到底锁定了什么?

在java.util.concurrent.Locks中使用API时,到底锁定了什么?,java,multithreading,Java,Multithreading,这可能是一个非常愚蠢的问题。我正在阅读java.util.concurrent.atomic和java.util.concurrent.locks包中接口和类的文档。我到处都能找到 void lock–获取锁(如果可用);如果锁不可用,线程将被阻塞,直到释放锁 我不确定的是,到底是什么资源被锁定了?代码片段示例显示 Lock lock = new ReentrantLock(); lock.lock(); try { // access to the shared resource }

这可能是一个非常愚蠢的问题。我正在阅读java.util.concurrent.atomic和java.util.concurrent.locks包中接口和类的文档。我到处都能找到

void lock–获取锁(如果可用);如果锁不可用,线程将被阻塞,直到释放锁

我不确定的是,到底是什么资源被锁定了?代码片段示例显示

Lock lock = new ReentrantLock(); 
lock.lock();
try {
    // access to the shared resource
} finally {
    lock.unlock();
}
在lock的调用下使用的任何东西都会被锁定吗?JVM是如何知道这一点的?如果在锁定和解锁之间有多个资源呢?我想我有这个问题,因为我是在读了同步之后读到的,它有一种非常具体的方式来说明要锁定什么,比如:synchronizedresourceReferenceThatNeedsToBeLocked


我做了很多研究,但没有找到这个问题的答案

您可以将您的代码看作是synchronized的优化版本。您正在锁定对象上进行同步,但以更有效的方式进行

请注意,当您使用synchronized时,对于synchronized块内部使用的资源没有任何保证。您只是锁定了一个特定的对象,该对象可能与您在同步块中使用的资源相同,也可能不同。本质上,不管是锁还是同步,您只是说确保在我完成之前,没有其他线程可以访问此块内同一实例上由同一锁或“同步”保护的代码或其他代码


要理解的关键是,无论是锁定还是同步,您都在保护一块代码不被并发访问。块内的代码可以访问一个或多个不同的资源;如果在其他地方使用相同的资源,则需要使用相同的锁来保护对它们的访问,或者在同一实例上进行同步,以确保安全。

锁始终与数据关联。如果没有数据,同步就没有意义。您有对象线程、锁、条件等。然后,您就有了数据结构,它在这些对象的帮助下是同步的。你需要完整的例子。在下面的示例中,我正在同步一个队列,所以添加到队列中的数据总是同步的。当然,它是从不同的线程添加到队列中的

import java.util.Deque;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;


public class BackgroundWorker {

    private Worker worker;
    private StringBuilder allData;

    @Before
    public void setUp() throws Exception {
        worker = new Worker(allData); // start databse worker
        worker.start();
    }

    @After
    public void tearDown() throws Exception {
        worker.stop();
    }

    public void logValue(final String data) {
        final LogValue logValue = new LogValue(data);
        worker.queue(logValue);
    }

    @Test
    public void test() {
        // very dummy, NOT multithreaded test 
        for (int i = 0; i < 10; i++) {
            logValue("Some data " + i);
        }
    }

    private static class Worker implements Runnable {

        private static final int MAX_QUEUE_SIZE = 1000;

        private final Deque<Job> queue = new LinkedList<Job>();
        private final Lock lock = new ReentrantLock();
        private final Condition jobAdded = lock.newCondition();
        private final Condition jobRemoved = lock.newCondition();
        private final StringBuilder dataSource;
        private final AtomicBoolean running = new AtomicBoolean(false);
        private Thread thread = null;

        Worker(final StringBuilder dataSource) {
            this.dataSource = dataSource;
        }

        @Override
        public void run() {

            processing: for (;;) {
                Job job;
                lock.lock();
                try {
                    while (null == (job = queue.pollFirst())) {
                        if (!running.get()) break processing;

                        try {
                            jobAdded.await();
                        } catch (InterruptedException ie) {
                            ie.printStackTrace();
                        }
                    }
                    jobRemoved.signal();
                }
                finally {
                    lock.unlock();
                }
                job.run(dataSource);
            }

        }

        void start() {
            lock.lock();
            try {
                if (running.getAndSet(true)) return; // already running
                thread = new Thread(this, "Database worker");
                thread.start();
            }
            finally {
                lock.unlock();
            }
        }

        void stop() {
            Thread runningThread;
            lock.lock();
            try {
                if (!running.getAndSet(false)) return; // already stopped
                runningThread = thread;
                thread = null;
                jobAdded.signal();
            }
            finally {
                lock.unlock();
            }

            // wait for the thread to finish while not holding a lock
            try {
                runningThread.join(2000); // we give it 2 seconds to empty its queue
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            runningThread.interrupt(); // we interrupt it just in case it hasn't finished yet
        }

        void queue(final Job job) {
            if (!running.get()) throw new IllegalStateException("Worker thread is not running");
            lock.lock();
            try {
                while (queue.size() >= MAX_QUEUE_SIZE) {
                    try {
                        jobRemoved.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                queue.addLast(job);
                jobAdded.signal();
            }
            finally {
                lock.unlock();
            }
        }
    }

    private static interface Job {

        void run(StringBuilder dataSource);
    }

    private static class LogValue implements Job {

        final String myData;

        LogValue(final String data) {
            this.myData = data;
        }

        @Override
        public void run(final StringBuilder dataSource) {
            dataSource.append(this.myData);
        }
    }

}
回答我的问题:

锁定的对象是引用变量lock所引用的对象。在本例中,是一个ReentrantLock对象

需要注意的一点是:

上面的代码可能会产生误导。在方法中创建一个新的锁对象将由相应的线程完成,并且相应的线程将只锁定在其堆栈中创建的对象。如果要锁定特定实例的变量或方法,则该实例应该有自己的锁定对象,并且只有相同的锁定对象应用于同步


有关更多信息,请参阅问题。请参阅相关锁的文档。

您能添加更多详细信息吗?为什么我要同步一个锁对象,而不是我的资源?这是否意味着,锁和解锁之间的所有可变资源都被当前线程锁定?添加了更多的说明。Re,…但以更有效的方式。这将是一个实施细节。没有什么可以阻止JRE以最有效的方式实现同步。使用显式锁对象为开发人员提供了更大的灵活性,但它们的速度并不是天生就快。没有资源被锁定,但执行某些指令的线程被阻止继续。线程只不过是一系列指令的独立执行。多个线程可能执行相同或不同的指令,这并不重要。如果他们想要访问由同一个锁保护的关键区域,他们将竞争该锁。无法获得锁的线程将等待锁再次可用并再次竞争。这可能会导致螺纹啮合,在最坏的情况下会导致死锁。