- 浏览: 71934 次
- 性别:
- 来自: 北京
文章分类
最新评论
copied from http://tutorials.jenkov.com/java-concurrency/locks.html
Notes:This tutorial is a very easy to read and understand version of java concurrent lock mechanism. I do suggest to take a look.
Locks in Java
By Jakob Jenkov
A lock is a thread synchronization mechanism like synchronized blocks except locks
can be more sophisticated than Java's synchronized blocks. Locks (and other more
advanced synchronization mechanisms) are created using synchronized blocks, so
it is not like we can get totally rid of the synchronized
keyword.
From Java 5 the
package java.util.concurrent
contains several lock implementations,
so you may not have to implement your own locks. But you will still need to know
how to use them, and it can still be useful to know the theory behind their
implementation.
Here is a list of the topics covered in this text:
A Simple Lock
Let's start out by looking at a synchronized block of Java code:
public class Counter{ private int count = 0; public int inc(){ synchronized(this){ return ++count; } } }
Notice the synchronized(this)
block in the inc()
method.
This block makes sure that only one thread can execute the return ++count
at a time. The code in the synchronized block could have been more advanced, but
the simple ++count
suffices to get the point across.
The Counter
class could have been written like this instead, using
a Lock
instead of a synchronized block:
public class Counter{ private Lock lock = new Lock(); private int count = 0; public int inc(){ lock.lock(); int newCount = ++count; lock.unlock(); return newCount; } }
The lock()
method locks the Lock
instance so that all
threads calling lock()
are blocked until unlock()
is
executed.
Here is a simple Lock
implementation:
public class Lock{ private boolean isLocked = false; public synchronized void lock() throws InterruptedException{ while(isLocked){ wait(); } isLocked = true; } public synchronized void unlock(){ isLocked = false; notify(); } }
Notice the while(isLocked)
loop, which is also called a
"spin lock". Spin locks and the methods wait()
and notify()
are covered in more detail in the text
Thread Signaling
. While isLocked
is true,
the thread calling lock()
is parked waiting in the wait()
call.
In case the thread should return unexpectedly from the wait() call without having
received a notify()
call (AKA a Spurious Wakeup
)
the thread re-checks the isLocked
condition to see if it is safe to
proceed or not, rather than just assume that being awakened means it is safe to proceed.
If isLocked
is false, the thread exits the while(isLocked)
loop,
and sets isLocked
back to true, to lock the Lock
instance for other
threads calling lock()
.
When the thread is done with the code in the critical section
(the code between lock()
and unlock()
), the thread calls unlock()
.
Executing unlock()
sets isLocked
back to false, and notifies (awakens) one of the
threads waiting in the wait()
call in the lock()
method, if any.
Lock Reentrance
Synchronized blocks in Java are reentrant. This means, that if a Java thread enters a synchronized block of code, and thereby take the lock on the monitor object the block is synchronized on, the thread can enter other Java code blocks synchronized on the same monitor object. Here is an example:
public class Reentrant{ public synchronized outer(){ inner(); } public synchronized inner(){ //do something } }
Notice how both outer()
and inner()
are declared synchronized,
which in Java is equivalent to a synchronized(this)
block.
If a thread calls outer()
there is no problem calling inner() from inside
outer()
, since both methods (or blocks) are synchronized on the same
monitor object ("this"). If a thread already holds the lock on a monitor object, it has
access to all blocks synchronized on the same monitor object. This is called reentrance.
The thread can reenter any block of code for which it already holds the lock.
The lock implementation shown earlier is not reentrant. If we rewrite the Reentrant
class like below, the thread calling outer()
will be blocked inside the
lock.lock()
in the inner()
method.
public class Reentrant2{ Lock lock = new Lock(); public outer(){ lock.lock(); inner(); lock.unlock(); } public synchronized inner(){ lock.lock(); //do something lock.unlock(); } }
A thread calling outer()
will first lock the Lock
instance. Then it
will call inner()
. Inside the inner()
method the thread will again
try to lock the Lock
instance. This will fail (meaning the thread will be blocked),
since the Lock
instance was locked already in the outer()
method.
The reason the thread will be blocked the second time it calls lock()
without
having called unlock()
in between, is apparent when we look at the lock()
implementation:
public class Lock{ boolean isLocked = false; public synchronized void lock() throws InterruptedException{ while(isLocked){ wait(); } isLocked = true; } ... }
It is the condition inside the while loop (spin lock) that determines if a thread is allowed to
exit the lock()
method or not. Currently the condition is that isLocked
must be false
for this to be allowed, regardless of what thread locked it.
To make the Lock
class reentrant we need to make a small change:
public class Lock{ boolean isLocked = false; Thread lockedBy = null; public synchronized void lock() throws InterruptedException{ Thread callingThread = Thread.currentThread(); while(isLocked && lockedBy != callingThread){ wait(); } isLocked = true; lockedBy = callingThread; } ... }
Notice how the while loop (spin lock) now also takes the thread that locked the Lock
instance into consideration. If either the lock is unlocked (isLocked
= false) or
the calling thread is the thread that locked the Lock
instance, the while loop
will not execute, and the thread calling lock()
will be allowed to exit the method.
The Lock
class is now reentrant.
Lock Fairness
Java's synchronized blocks makes no guarantees about the sequence in which threads trying to enter them
are granted access. Therefore, if many threads are constantly competing for access to the same
synchronized block, there is a risk that one or more of the threads are never granted access - that
access is always granted to other threads. This is called starvation. To avoid this a Lock
should be fair.
Since the Lock
implementations shown in this text uses synchronized blocks internally, they do not guarantee
fairness. Starvation and fairness are discussed in more detail in the text
Starvation and Fairness
.
Calling unlock() From a finally-clause
When guarding a critical section with a Lock
, and the critical section may throw exceptions,
it is important to call the unlock()
method from inside a finally
-clause. Doing so makes
sure that the Lock
is unlocked so other threads can lock it. Here is an example:
lock.lock(); try{ //do critical section code, which may throw exception } finally { lock.unlock(); }
This little construct makes sure that the Lock
is unlocked in case an
exception is thrown from the code in the critical section. If unlock()
was not called from inside a finally
-clause, and an exception was thrown
from the critical section, the Lock
would remain locked forever, causing
all threads calling lock()
on that Lock
instance to halt
indefinately. The only thing that could unlock the Lock
again would be if the
Lock
is reentrant, and the thread that had it locked when the exception
was thrown, later succeeds in locking it, executing the critical section and calling unlock()
again afterwards. That would unlock the Lock
again. But why wait for that
to happen, if
it happens? Calling unlock()
from a finally
-clause
is a much more robust solution.
发表评论
-
How to be a Programmer: A Short,Comprehensive,and Personal Summary
2013-10-28 10:38 587well written. http://samizdat ... -
js module pattern
2013-10-12 16:21 398http://www.adequatelygood.com/ ... -
GZip compressing HTML, JavaScript, CSS etc. makes the data sent to the browser s
2013-07-31 15:48 660this is fun. http://tutorials ... -
java collection matrix
2012-08-07 11:24 745http://www.janeve.me/articles/w ... -
ghost text (aka in-field text)
2012-04-01 11:18 697http://archive.plugins.jquery.c ... -
What is Optimistic Locking vs. Pessimistic Locking
2011-09-09 16:50 834What is Optimistic Locking vs. ... -
what is DAO
2011-04-15 13:42 768http://java.sun.com/blueprints/ ... -
indenting xml in vim with xmllint
2011-01-10 09:48 708I added to my “.vimrc” file: ... -
css sprite
2010-12-15 16:57 665http://css-tricks.com/css-sprit ... -
最牛B 的 Linux Shell 命令
2010-10-30 00:08 714http://hi.baidu.com/hy0kl/blog/ ... -
GPS Bearing VS Heading
2010-10-21 15:40 1675http://gps.about.com/od/glossar ... -
Document Type Declaration
2010-07-19 22:01 832Document Type Declaration h ... -
XML Declaration must be the first line in the document.
2010-06-12 17:54 901The XML declaration typically a ... -
UCM
2010-05-08 11:41 745Two links about UCM The power ... -
What is an MXBean?
2010-01-28 11:10 762refer to http://weblogs.java. ... -
why wait() always in a loop
2010-01-19 00:17 843As we know ,jdk API doc suggest ... -
use jps instead of ps to find jvm process
2010-01-11 14:21 816copied from http://java.sun.com ... -
My first error of Hello Wolrd Struts
2010-01-04 09:10 866It's my first time to touch Str ... -
Unit Testing Equals and HashCode of Java Beans
2009-12-29 10:07 1308copy from http://blog.cornetdes ... -
communicate between plug-ins in different sandboxes
2009-12-17 21:17 681Given that there are many cases ...
相关推荐
6. **多线程**:Java提供了丰富的API来支持并发编程,如Thread类、synchronized关键字、volatile变量、Lock接口等。习题会涵盖同步控制、线程通信等复杂问题。 7. **输入/输出(I/O)**:Java的I/O系统包括文件操作、...
《Thinking in Java》是Bruce Eckel的经典著作,它深入浅出地介绍了Java编程语言的核心概念和技术,对于初学者和有经验的程序员都是极好的学习资源。文档内容涵盖了许多关键知识点,包括但不限于: 1. **基础语法**...
《Thinking in Java》是Bruce Eckel的经典之作,它深入浅出地介绍了Java语言的核心概念和技术。这本书的第四版更是被广大Java开发者视为学习和进阶的重要参考资料。源码是书中理论知识的实践体现,通过阅读和理解...
《The Thinking in Java》是 Bruce Eckel 所著的一本经典Java编程教材,以其深入浅出的讲解方式深受程序员喜爱。这本书旨在引导读者深入理解Java语言的核心概念和机制,不仅覆盖了基础语法,还包括高级特性如多线程...
5. **多线程篇**:介绍Java并发编程的基础,包括线程的创建、同步机制(如synchronized关键字和Lock接口)以及并发工具类,如Semaphore、ExecutorService等。 6. **输入/输出篇**:探讨Java的I/O流系统,包括文件I/...
《Thinking in Java》是 Bruce Eckel 的经典著作,其中第21章主要讲解了Java中的并发编程知识。并发编程是让程序在多个线程中同时执行任务,以提高程序的效率和响应性。以下是该章节的重点知识点: 1. **并发的多面...
《Data Structures and Algorithms in Java》是一本专注于Java编程语言中的数据结构与算法的权威书籍,由Michael T. Goodrich和Roberto Tamassia合著,第五版提供了全面且深入的讲解。这本书对于学习和理解如何在...
《Thinking in Java》是Bruce Eckel的经典编程教材,第三版(edition3)深入浅出地介绍了Java编程语言的核心概念和技术。这个压缩包文件包含了书中所提及的示例代码,名为"TIJcode",这对于理解和实践书中理论知识至...
书中会讲解监视器(Monitor)、锁(Lock)、条件变量(Condition)以及它们在`synchronized`关键字中的应用。 3. **线程安全**:线程安全的类或方法能够正确处理多线程环境下的并发访问。书中讨论了线程安全的层次...
很抱歉,但根据您给出的信息,标题"Thinking in java 1"和描述"Thinking in java JAVA学习的最好教材,没有之一"明显与压缩包子文件的文件名称"叛逆的鲁路修Stories.mp4"不符。"Thinking in Java"通常指的是Bruce ...
这通常通过同步机制实现,如`synchronized`关键字、`volatile`变量、`Lock`接口等。 2. **最小化锁的使用**:尽可能减少对共享资源的锁定,以提高并行性。例如,使用无锁数据结构或原子操作(`java.util.concurrent...
7. **多线程**:Java提供了内置的多线程支持,包括Thread类和Runnable接口,以及同步机制如synchronized关键字和Lock接口。 8. **网络编程**:Java的Socket编程使得创建网络应用变得简单,书中的这部分可能会讲解...
《Thinking in Java》是Bruce Eckel创作的一本Java编程经典教程,深受全球程序员喜爱,尤其适合初学者和有经验的开发者深入理解Java语言。这本书以其深入浅出的讲解方式,全面覆盖了Java语言的核心概念、语法和编程...
6. **多线程**:Java提供了并发编程的支持,包括Thread类和Runnable接口,以及同步机制(如synchronized关键字、wait/notify机制和Lock接口)。源码将展示如何创建和管理线程。 7. **网络编程**:Java的Socket和...
5. **多线程**:Java提供了强大的多线程支持,包括线程的创建、同步机制(如synchronized关键字、wait/notify、Lock接口等)。理解并发编程对于开发高效系统至关重要。 6. **输入/输出**:包括I/O流的分类、文件...
《Thinking in Java 3》是Java编程领域里一本经典的教程,由Bruce Eckel撰写,它深入浅出地讲解了Java语言的核心概念和技术。这本书对于初学者和有经验的程序员来说都是一个宝贵的资源,因为它不仅涵盖了基础语法,...
6. **多线程**:Java支持多线程编程,书中介绍了Thread类、Runnable接口以及同步机制,如synchronized关键字和Lock接口,帮助理解并发执行的概念。 7. **输入/输出流**:书中阐述了Java的I/O系统,包括文件操作、...
《Thinking in Java 3rd Edition》是一本深受程序员喜爱的经典Java编程教材,由Bruce Eckel撰写,旨在深入讲解Java语言的核心概念和编程思想。这本书以其详尽的解释、丰富的示例和深入的讨论,帮助读者建立起坚实的...
《Thinking in Java》是Bruce Eckel的经典编程教材,它深入浅出地介绍了Java语言的核心概念和技术。这本书的第四版更是涵盖了Java的最新发展,包括泛型、枚举、注解等。现在,我们来详细探讨一下这个压缩包文件中...
《Thinking in Java》是Bruce Eckel创作的一本经典Java编程教程,被誉为学习Java的宝典。这本书的第三版深入浅出地介绍了Java语言的核心概念和技术,对于初学者和经验丰富的开发者来说,都是极具价值的学习资源。 ...