Java多线系列文章是Java多线程的详解介绍,对多线程还不熟悉的同学可以先去看一下我的这篇博客 Java基础系列3:多线程超详细总结 ,这篇博客从宏观层面介绍了多线程的整体概况,接下来的几篇文章是对多线程的深入剖析。
1、从Java5开始,Java提供了一种功能更强大的线程同步机制——通过显式定义同步锁对象来实现同步,在这种机制下,同步锁由Lock对象充当。 2、Lock 提供了比synchronized方法和synchronized代码块更广泛的锁定操作,Lock允许实现更灵活的结构,可以具有差别很大的属性,并且支持多个相关的Condition对象。 3、Lock是控制多个线程对共享资源进行访问的工具。通常,锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。 4、某些锁可能允许对共享资源并发访问,如ReadWriteLock(读写锁),Lock、ReadWriteLock是Java5提供的两个根接口,并为Lock 提供了ReentrantLock(可重入锁)实现类,为ReadWriteLock提供了ReentrantReadWriteLock 实现类。 5、Java8新增了新型的StampedLock类,在大多数场景中它可以替代传统的ReentrantReadWriteLock。ReentrantReadWriteLock 为读写操作提供了三种锁模式:Writing、ReadingOptimistic、Reading。
class
X{
//定义锁对象
private
final
ReentrantLock lock=
new
ReentrantLock();
//定义需要保证线程安全的方法
public
void
m() {
//加锁
lock.lock();
try
{
//需要保证线程安全的代码
}
finally
{
lock.unlock();
}
}
}
在Java多线程中,可以使用synchronized关键字来实现线程之间同步互斥,但在JDK1.5中新增加了ReentrantLock类也能达到同样的效果,并且在扩展功能上也更加强大,比如具有嗅探锁定、多路分支通知等功能,而且在使用上也比synchronized更加的灵活。
既然ReentrantLock类在功能上相比synchronized更多,那么就以一个初步的程序示例来介绍一下ReentrantLock类的使用。
import
java.util.concurrent.locks.Lock;
import
java.util.concurrent.locks.ReentrantLock;
class
MyService{
private
Lock lock=
new
ReentrantLock();
public
void
testMethod() {
lock.lock();
for
(
int
i=
0
;i<
5
;i++) {
System.out.println(
"ThreadName= "
+Thread.currentThread().getName()+(
" "
+(i+
1
)));
}
lock.unlock();
}
}
class
MyThread
extends
Thread{
private
MyService service;
public
MyThread(MyService service) {
this
.service=service;
}
@Override
public
void
run() {
service.testMethod();
}
}
public
class
LockTest {
public
static
void
main(String[] args) {
MyService service=
new
MyService();
MyThread t1=
new
MyThread(service);
MyThread t2=
new
MyThread(service);
MyThread t3=
new
MyThread(service);
MyThread t4=
new
MyThread(service);
MyThread t5=
new
MyThread(service);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
运行结果:
ThreadName= Thread-
2
1
ThreadName= Thread-
2
2
ThreadName= Thread-
2
3
ThreadName= Thread-
2
4
ThreadName= Thread-
2
5
ThreadName= Thread-
0
1
ThreadName= Thread-
0
2
ThreadName= Thread-
0
3
ThreadName= Thread-
0
4
ThreadName= Thread-
0
5
ThreadName= Thread-
3
1
ThreadName= Thread-
3
2
ThreadName= Thread-
3
3
ThreadName= Thread-
3
4
ThreadName= Thread-
3
5
ThreadName= Thread-
4
1
ThreadName= Thread-
4
2
ThreadName= Thread-
4
3
ThreadName= Thread-
4
4
ThreadName= Thread-
4
5
ThreadName= Thread-
1
1
ThreadName= Thread-
1
2
ThreadName= Thread-
1
3
ThreadName= Thread-
1
4
ThreadName= Thread-
1
5
从运行的结果来看,当前线程打印完毕之后将锁进行释放,其他线程才可以继续打印。线程打印的数据是分组打印,因为当前线程已经持有锁,但线程之间打印的顺序是随机的。lock.lock()是对当前线程加锁,当线程执行完毕后调用lock.unlock()释放锁,这时候其他线程可以去获取锁,至于是哪一个线程可以争抢到锁还是看CPU的调度
关键字synchronized与wait()和notify()/notifyAll()方法相结合可以实现等待/通知模式,类ReentrantLock也可以实现同样的功能,但需要借助于Condition对象。Condition类是在JDK5中出现的技术,使用它有更好的灵活性,比如可以实现多路通知功能,也就是在一个Lock对象里面可以创建多个Condition(即对象监视器)实例,线程对象可以注册在指定的Condition中,从而可以有选择性地进行线程通知,在调度线程上更加灵活。
在使用notify(O/notifyAll0方法进行通知时,被通知的线程却是由JVM随机选择的。但使用ReentrantLock结合Condition类是可以实现前面介绍过的“选择性通知”,这个功能是非常重要的,而且在Condition类中是默认提供的。
而synchronized就相当于整个Lock对象中只有一个单一的Condition对象,所有的线程都注册在它一个对象的身上。线程开始notifyAll()时,需要通知所有的WAITING线程,没有选择权,会出现相当大的效率问题。
package
Thread05;
import
java.util.concurrent.locks.Condition;
import
java.util.concurrent.locks.Lock;
import
java.util.concurrent.locks.ReentrantLock;
class
MyService{
private
Lock lock=
new
ReentrantLock();
private
Condition condition=lock.newCondition();
public
void
await() {
try
{
lock.lock();
System.out.println(
"A"
);
condition.await();
System.out.println(
"B"
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
finally
{
lock.unlock();
System.out.println(
"锁释放了"
);
}
}
}
class
MyThread
extends
Thread{
private
MyService service;
public
MyThread(MyService service) {
this
.service=service;
}
@Override
public
void
run() {
service.await();
}
}
public
class
LockTest {
public
static
void
main(String[] args) {
MyService service=
new
MyService();
MyThread thread=
new
MyThread(service);
thread.start();
}
}
输出结果:
我们可以看到输出结果只有一个A,并没有其他的输出,这是因为调用Condition的await()方法,使当前执行任务的线程进入了等待的状态
import
java.util.concurrent.locks.Condition;
import
java.util.concurrent.locks.Lock;
import
java.util.concurrent.locks.ReentrantLock;
class
MyService{
private
Lock lock=
new
ReentrantLock();
private
Condition condition=lock.newCondition();
public
void
await() {
try
{
lock.lock();
System.out.println(
"await时间为"
+System.currentTimeMillis());
condition.await();
}
catch
(InterruptedException e) {
e.printStackTrace();
}
finally
{
lock.unlock();
System.out.println(
"锁释放了"
);
}
}
public
void
signal() {
try
{
lock.lock();
System.out.println(
"signal时间为"
+System.currentTimeMillis());
condition.signal();
}
finally
{
lock.unlock();
}
}
}
class
MyThread
extends
Thread{
private
MyService service;
public
MyThread(MyService service) {
this
.service=service;
}
@Override
public
void
run() {
service.await();
}
}
public
class
LockTest {
public
static
void
main(String[] args)
throws
InterruptedException {
MyService service=
new
MyService();
MyThread thread=
new
MyThread(service);
thread.start();
Thread.sleep(
3000
);
service.signal();
}
}
运行结果:
await时间为
1575599786039
signal时间为
1575599789051
锁释放了
成功实现等待/通知模式
Object类中的wait()方法相当于Condition类中的await()方法,Object类中的wait(long timeout)方法相当于Condition类中的await(long time,TimeUnit unit)方法。Object类中的notify()方法相当于Condition类中的signal()方法。Object类中的notifyAll()方法相当于Condition类中的signalAll()方法。
前面使用一个Condition对象来实现等待/通知模式,其实Condition对象也可以创建多个。那么一个Condition对象和多个Condition对象在使用上有什么区别呢?
import
java.util.concurrent.locks.Condition;
import
java.util.concurrent.locks.Lock;
import
java.util.concurrent.locks.ReentrantLock;
class
MyService{
private
Lock lock=
new
ReentrantLock();
private
Condition condition=lock.newCondition();
public
void
awaitA() {
try
{
lock.lock();
System.out.println(
"begin awaitA时间为"
+System.currentTimeMillis()+
"ThreadName"
+Thread.currentThread().getName());
condition.await();
System.out.println(
"end awaitA时间为"
+System.currentTimeMillis()+
"ThreadName"
+Thread.currentThread().getName());
}
catch
(InterruptedException e) {
e.printStackTrace();
}
finally
{
lock.unlock();
}
}
public
void
awaitB() {
try
{
lock.lock();
System.out.println(
"begin awaitB时间为"
+System.currentTimeMillis()+
"ThreadName"
+Thread.currentThread().getName());
condition.await();
System.out.println(
"end awaitB时间为"
+System.currentTimeMillis()+
"ThreadName"
+Thread.currentThread().getName());
}
catch
(InterruptedException e) {
e.printStackTrace();
}
finally
{
lock.unlock();
}
}
public
void
signalAll() {
try
{
lock.lock();
System.out.println(
"signalAll时间为"
+System.currentTimeMillis());
condition.signalAll();
}
finally
{
lock.unlock();
}
}
}
class
MyThreadA
extends
Thread{
private
MyService service;
public
MyThreadA(MyService service) {
this
.service=service;
}
@Override
public
void
run() {
service.awaitA();
}
}
class
MyThreadB
extends
Thread{
private
MyService service;
public
MyThreadB(MyService service) {
this
.service=service;
}
@Override
public
void
run() {
service.awaitB();
}
}
public
class
LockTest {
public
static
void
main(String[] args)
throws
InterruptedException {
MyService service=
new
MyService();
MyThreadA threadA=
new
MyThreadA(service);
threadA.setName(
"A"
);
threadA.start();
MyThreadB threadB=
new
MyThreadB(service);
threadB.setName(
"B"
);
threadB.start();
Thread.sleep(
3000
);
service.signalAll();
}
}
运行结果:
begin awaitA时间为1575600904529ThreadNameA
begin awaitB时间为1575600904545ThreadNameB
signalAll时间为
1575600907537
end awaitA时间为1575600907537ThreadNameA
end awaitB时间为1575600907537ThreadNameB
import
java.util.concurrent.locks.Condition;
import
java.util.concurrent.locks.Lock;
import
java.util.concurrent.locks.ReentrantLock;
class
MyService{
private
Lock lock=
new
ReentrantLock();
private
Condition conditionA=lock.newCondition();
private
Condition conditionB=lock.newCondition();
public
void
awaitA() {
try
{
lock.lock();
System.out.println(
"begin awaitA时间为"
+System.currentTimeMillis()+
"ThreadName"
+Thread.currentThread().getName());
conditionA.await();
System.out.println(
"end awaitA时间为"
+System.currentTimeMillis()+
"ThreadName"
+Thread.currentThread().getName());
}
catch
(InterruptedException e) {
e.printStackTrace();
}
finally
{
lock.unlock();
}
}
public
void
awaitB() {
try
{
lock.lock();
System.out.println(
"begin awaitB时间为"
+System.currentTimeMillis()+
"ThreadName"
+Thread.currentThread().getName());
conditionB.await();
System.out.println(
"end awaitB时间为"
+System.currentTimeMillis()+
"ThreadName"
+Thread.currentThread().getName());
}
catch
(InterruptedException e) {
e.printStackTrace();
}
finally
{
lock.unlock();
}
}
//通知A
public
void
signalAll_A() {
try
{
lock.lock();
System.out.println(
"signalAll_A时间为"
+System.currentTimeMillis()+
"ThreadName="
+Thread.currentThread().getName());
conditionA.signalAll();
}
finally
{
lock.unlock();
}
}
//通知B
public
void
signalAll_B() {
try
{
lock.lock();
System.out.println(
"signalAll_A时间为"
+System.currentTimeMillis()+
"ThreadName="
+Thread.currentThread().getName());
conditionA.signalAll();
}
finally
{
lock.unlock();
}
}
}
class
MyThreadA
extends
Thread{
private
MyService service;
public
MyThreadA(MyService service) {
this
.service=service;
}
@Override
public
void
run() {
service.awaitA();
}
}
class
MyThreadB
extends
Thread{
private
MyService service;
public
MyThreadB(MyService service) {
this
.service=service;
}
@Override
public
void
run() {
service.awaitB();
}
}
public
class
LockTest {
public
static
void
main(String[] args)
throws
InterruptedException {
MyService service=
new
MyService();
MyThreadA threadA=
new
MyThreadA(service);
threadA.setName(
"A"
);
threadA.start();
MyThreadB threadB=
new
MyThreadB(service);
threadB.setName(
"B"
);
threadB.start();
Thread.sleep(
3000
);
service.signalAll_A();
}
}
运行结果:
begin awaitA时间为1575601785167ThreadNameA
begin awaitB时间为1575601785167ThreadNameB
signalAll_A时间为1575601788181ThreadName=main
end awaitA时间为1575601788181ThreadNameA
上面的代码实现通知部分线程,定义了两个Condition,在测试类中只是唤醒了A,从输出结果可以看出,线程A被唤醒了,线程B依然处于等待状态
import
java.util.concurrent.locks.Condition;
import
java.util.concurrent.locks.Lock;
import
java.util.concurrent.locks.ReentrantLock;
class
MyService{
private
Lock lock=
new
ReentrantLock();
private
Condition condition=lock.newCondition();
private
boolean
hasValue=
false
;
public
void
set() {
try
{
lock.lock();
while
(hasValue==
true
) {
condition.await();
}
System.out.println(
"打印★"
);
hasValue=
true
;
condition.signal();
}
catch
(Exception e) {
e.printStackTrace();
}
finally
{
lock.unlock();
}
}
public
void
get() {
try
{
lock.lock();
while
(hasValue==
false
) {
condition.await();
}
System.out.println(
"打印☆"
);
hasValue=
false
;
condition.signal();
}
catch
(Exception e) {
e.printStackTrace();
}
finally
{
lock.unlock();
}
}
}
class
MyThreadA
extends
Thread{
private
MyService service;
public
MyThreadA(MyService service) {
this
.service=service;
}
@Override
public
void
run() {
for
(
int
i=
0
;i<Integer.MAX_VALUE;i++) {
service.set();
}
}
}
class
MyThreadB
extends
Thread{
private
MyService service;
public
MyThreadB(MyService service) {
this
.service=service;
}
@Override
public
void
run() {
for
(
int
i=
0
;i<Integer.MAX_VALUE;i++) {
service.get();
}
}
}
public
class
LockTest {
public
static
void
main(String[] args)
throws
InterruptedException {
MyService service=
new
MyService();
MyThreadA a=
new
MyThreadA(service);
a.start();
MyThreadB b=
new
MyThreadB(service);
b.start();
}
}
运行结果:
上面代码实现了生产者消费者的功能,一个生产一个消费,如果hasValue=false相当于生产者没有生产产品,当前没有可消费的产品,所以调用生产者生产,当hasValue=true说明当前有产品还没有被消费,那么生产者应该停止生产,调用消费者消费
import
java.util.concurrent.locks.Condition;
import
java.util.concurrent.locks.Lock;
import
java.util.concurrent.locks.ReentrantLock;
class
MyService{
private
Lock lock=
new
ReentrantLock();
private
Condition condition=lock.newCondition();
private
boolean
hasValue=
false
;
public
void
set() {
try
{
lock.lock();
while
(hasValue==
true
) {
System.out.println(
"有可能★★连续"
);
condition.await();
}
System.out.println(
"打印★"
);
hasValue=
true
;
condition.signal();
}
catch
(Exception e) {
e.printStackTrace();
}
finally
{
lock.unlock();
}
}
public
void
get() {
try
{
lock.lock();
while
(hasValue==
false
) {
System.out.println(
"有可能☆☆连续"
);
condition.await();
}
System.out.println(
"打印☆"
);
hasValue=
false
;
condition.signal();
}
catch
(Exception e) {
e.printStackTrace();
}
finally
{
lock.unlock();
}
}
}
class
MyThreadA
extends
Thread{
private
MyService service;
public
MyThreadA(MyService service) {
this
.service=service;
}
@Override
public
void
run() {
for
(
int
i=
0
;i<Integer.MAX_VALUE;i++) {
service.set();
}
}
}
class
MyThreadB
extends
Thread{
private
MyService service;
public
MyThreadB(MyService service) {
this
.service=service;
}
@Override
public
void
run() {
for
(
int
i=
0
;i<Integer.MAX_VALUE;i++) {
service.get();
}
}
}
public
class
LockTest {
public
static
void
main(String[] args)
throws
InterruptedException {
MyService service=
new
MyService();
MyThreadA[] threadA=
new
MyThreadA[
10
];
MyThreadB[] threadB=
new
MyThreadB[
10
];
for
(
int
i=
0
;i<
10
;i++) {
threadA[i]=
new
MyThreadA(service);
threadB[i]=
new
MyThreadB(service);
threadA[i].start();
threadB[i].start();
}
}
}
运行结果:
运行程序后出现了假死,因为出现了 生产者 释放 生产者 或者 消费者 释放 消费者 的情况,那么该如何解决这个问题呢?在使用synchronized实现生产者消费者的时候我们也遇到过这种情况,当时是使用notifyAll()来解决这个问题的,那么现在使用锁我们则用signalAll()方法来解决死锁问题,将上述代码中signal()方法改成signalAll()即可
修改后程序运行结果如下
程序一直正常运行,没有出现死锁情况
公平与非公平锁:锁Lock分为“公平锁”和“非公平锁”,公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的FIFO先进先出顺序。而非公平锁就是一种获取锁的抢占机制,是随机获得锁的,和公平锁不一样的就是先来的不一定先得到锁,这个方式可能造成某些线程一直拿不到锁,结果也就是不公平的了。
创建公平锁和非公平锁ReentrantLock lock=new ReentrantLock(boolean a),创建锁时如果a为true的话,则创建的是公平锁,如果a为false的话,则创建的是非公平锁
import
java.util.concurrent.locks.ReentrantLock;
class
Service{
private
ReentrantLock lock;
public
Service(
boolean
isFair) {
lock=
new
ReentrantLock(isFair);
}
public
void
serviceMethod() {
try
{
lock.lock();
System.out.println(
"ThreadName="
+Thread.currentThread().getName()+
"获得锁定"
);
}
catch
(Exception e) {
e.printStackTrace();
}
finally
{
lock.unlock();
}
}
}
public
class
LockTest {
public
static
void
main(String[] args)
throws
InterruptedException {
final
Service service=
new
Service(
true
);
Runnable runnable=
new
Runnable() {
@Override
public
void
run() {
System.out.println(
"★线程"
+Thread.currentThread().getName()+
"运行了"
);
service.serviceMethod();
}
};
Thread[] threadArray=
new
Thread[
10
];
for
(
int
i=
0
;i<
10
;i++) {
threadArray[i]=
new
Thread(runnable);
}
for
(
int
i=
0
;i<
10
;i++) {
threadArray[i].start();
}
}
}
运行结果:
★线程Thread-
2
运行了
★线程Thread-
3
运行了
★线程Thread-
0
运行了
★线程Thread-
9
运行了
★线程Thread-
4
运行了
★线程Thread-
8
运行了
★线程Thread-
5
运行了
★线程Thread-
1
运行了
★线程Thread-
6
运行了
★线程Thread-
7
运行了
ThreadName=Thread-
2
获得锁定
ThreadName=Thread-
6
获得锁定
ThreadName=Thread-
1
获得锁定
ThreadName=Thread-
8
获得锁定
ThreadName=Thread-
0
获得锁定
ThreadName=Thread-
7
获得锁定
ThreadName=Thread-
5
获得锁定
ThreadName=Thread-
3
获得锁定
ThreadName=Thread-
9
获得锁定
ThreadName=Thread-
4
获得锁定
结果显示输出基本是呈有序的状态,这就是公平锁的特点
import
java.util.concurrent.locks.ReentrantLock;
class
Service{
private
ReentrantLock lock;
public
Service(
boolean
isFair) {
lock=
new
ReentrantLock(isFair);
}
public
void
serviceMethod() {
try
{
lock.lock();
System.out.println(
"ThreadName="
+Thread.currentThread().getName()+
"获得锁定"
);
}
catch
(Exception e) {
e.printStackTrace();
}
finally
{
lock.unlock();
}
}
}
public
class
LockTest {
public
static
void
main(String[] args)
throws
InterruptedException {
final
Service service=
new
Service(
false
);
Runnable runnable=
new
Runnable() {
@Override
public
void
run() {
System.out.println(
"★线程"
+Thread.currentThread().getName()+
"运行了"
);
service.serviceMethod();
}
};
Thread[] threadArray=
new
Thread[
10
];
for
(
int
i=
0
;i<
10
;i++) {
threadArray[i]=
new
Thread(runnable);
}
for
(
int
i=
0
;i<
10
;i++) {
threadArray[i].start();
}
}
}
运行结果:
★线程Thread-
2
运行了
★线程Thread-
9
运行了
★线程Thread-
7
运行了
★线程Thread-
0
运行了
★线程Thread-
3
运行了
★线程Thread-
1
运行了
★线程Thread-
6
运行了
★线程Thread-
5
运行了
★线程Thread-
4
运行了
ThreadName=Thread-
1
获得锁定
★线程Thread-
8
运行了
ThreadName=Thread-
8
获得锁定
ThreadName=Thread-
2
获得锁定
ThreadName=Thread-
7
获得锁定
ThreadName=Thread-
5
获得锁定
ThreadName=Thread-
3
获得锁定
ThreadName=Thread-
4
获得锁定
ThreadName=Thread-
9
获得锁定
ThreadName=Thread-
0
获得锁定
ThreadName=Thread-
6
获得锁定
非公平锁的运行结果基本上是乱序的,说明先start()启动的线程不代表先获得锁
(1)、int getHoldCount()
getHoldCount()的作用是查询当前线程保持此锁定的个数,也就是调用lock()方法的次数。
(2)、int getQueueLength()
getQueueLength()的作用是返回正等待获取此锁定的线程估计数,比如有5个线程,1个线程首先执行awai()方法,那么在调用getQueueLength()方法后返回值是4,说明有4个线程同时在等待lock的释放。
(3)、int getWaitQueueLength(Condition condition)
getWaitQueueLength(Condition condition)的作用是返回等待与此锁定相关的给定条件Condition的线程估计数,比如有5个线程,每个线程都执行了同一个condition对象的await()方法,则调用getWaitQueueLength(Condition condition)方法时返回的int值是5。
(4)、boolean hasQueuedThread(Thread thread)
hasQueuedThread(Thread thread)的作用是查询指定的线程是否正在等待获取此锁定
hasQueuedThreads()的作用是查询是否有线程正在等待获取此锁定。
(5)、boolean hasWaiters(Condition condition)
hasWaiters(Condition condition)的作用是查询是否有线程正在等待与此锁定有关的condition条件。
(6)、boolean isFair()
isFair()的作用是判断是不是公平锁
(7)、boolean isHeldByCurrentThread()
isHeldByCurrentThread的作用是查询当前线程是否保持此锁定
(8)、boolean isLocked()
isLocked()的作用是查询此锁定是否由任意的线程保持
类ReentrantLock具有完全互斥排他的效果,即同一时间只有一个线程在执行ReentrantLock.lock()方法后面的任务。这样做虽然保证了实例变量的线程安全性,但效率却是非常低下的。所以在JDK中提供了一种读写锁ReentrantReadWriteLock类,使用它可以加快运行效率,在某些不需要操作实例变量的方法中,完全可以使用读写锁ReentrantReadWriteLock 来提升该方法的代码运行速度。
读写锁表示也有两个锁,一个是读操作相关的锁,也称为共享锁;另一个是写操作相关的锁,也叫排他锁。也就是多个读锁之间不互斥,读锁与写锁互斥,写锁与写锁互斥。在没有线程Thread进行写入操作时,进行读取操作的多个Thread都可以获取读锁,而进行写入操作的Thread只有在获取写锁后才能进行写入操作。即多个Thread可以同时进行读取操作,但是同一时刻只允许一个Thread进行写入操作。
import
java.util.concurrent.locks.ReentrantReadWriteLock;
class
Service{
private
ReentrantReadWriteLock lock=
new
ReentrantReadWriteLock();
public
void
read() {
try
{
try
{
lock.readLock().lock();
System.out.println(
"获取读锁"
+Thread.currentThread().getName()+
" "
+System.currentTimeMillis());
Thread.sleep(
10000
);
}
finally
{
lock.readLock().unlock();
}
}
catch
(Exception e) {
e.printStackTrace();
}
}
}
class
MyThreadA
extends
Thread{
private
Service service;
public
MyThreadA(Service service) {
this
.service=service;
}
@Override
public
void
run() {
service.read();
}
}
class
MyThreadB
extends
Thread{
private
Service service;
public
MyThreadB(Service service) {
this
.service=service;
}
@Override
public
void
run() {
service.read();
}
}
public
class
LockTest {
public
static
void
main(String[] args)
throws
InterruptedException {
Service service=
new
Service();
MyThreadA a=
new
MyThreadA(service);
a.setName(
"A"
);
MyThreadB b=
new
MyThreadB(service);
b.setName(
"B"
);
a.start();
b.start();
}
}
运行结果:
获取读锁A
1575611161158
获取读锁B
1575611161158
从输出结果打印的时间来看,两个线程几乎同时进入lock()方法后面的代码。说明在此使用了lock.readLock()读锁可以提高程序运行效率,允许多个线程同时执行lock()方法后面的代码。
import
java.util.concurrent.locks.ReentrantReadWriteLock;
class
Service{
private
ReentrantReadWriteLock lock=
new
ReentrantReadWriteLock();
public
void
write() {
try
{
try
{
lock.writeLock().lock();
System.out.println(
"获取写锁"
+Thread.currentThread().getName()+
" "
+System.currentTimeMillis());
Thread.sleep(
10000
);
}
finally
{
lock.writeLock().unlock();
}
}
catch
(Exception e) {
e.printStackTrace();
}
}
}
class
MyThreadA
extends
Thread{
private
Service service;
public
MyThreadA(Service service) {
this
.service=service;
}
@Override
public
void
run() {
service.write();
}
}
class
MyThreadB
extends
Thread{
private
Service service;
public
MyThreadB(Service service) {
this
.service=service;
}
@Override
public
void
run() {
service.write();
}
}
public
class
LockTest {
public
static
void
main(String[] args)
throws
InterruptedException {
Service service=
new
Service();
MyThreadA a=
new
MyThreadA(service);
a.setName(
"A"
);
MyThreadB b=
new
MyThreadB(service);
b.setName(
"B"
);
a.start();
b.start();
}
}
运行结果:
获取写锁B
1575611458260
获取写锁A
1575611468273
结果显示写锁的效果是同一时间只允许一个线程执行lock()后面的代码
import
java.util.concurrent.locks.ReentrantReadWriteLock;
class
Service{
private
ReentrantReadWriteLock lock=
new
ReentrantReadWriteLock();
public
void
read() {
try
{
try
{
lock.readLock().lock();
System.out.println(
"获取读锁"
+Thread.currentThread().getName()+
" "
+System.currentTimeMillis());
Thread.sleep(
10000
);
}
finally
{
lock.readLock().unlock();
}
}
catch
(Exception e) {
e.printStackTrace();
}
}
public
void
write() {
try
{
try
{
lock.writeLock().lock();
System.out.println(
"获取写锁"
+Thread.currentThread().getName()+
" "
+System.currentTimeMillis());
Thread.sleep(
10000
);
}
finally
{
lock.writeLock().unlock();
}
}
catch
(Exception e) {
e.printStackTrace();
}
}
}
class
MyThreadA
extends
Thread{
private
Service service;
public
MyThreadA(Service service) {
this
.service=service;
}
@Override
public
void
run() {
service.read();
}
}
class
MyThreadB
extends
Thread{
private
Service service;
public
MyThreadB(Service service) {
this
.service=service;
}
@Override
public
void
run() {
service.write();
}
}
public
class
LockTest {
public
static
void
main(String[] args)
throws
InterruptedException {
Service service=
new
Service();
MyThreadA a=
new
MyThreadA(service);
a.setName(
"A"
);
MyThreadB b=
new
MyThreadB(service);
b.setName(
"B"
);
a.start();
b.start();
}
}
运行结果:
获取读锁A 1575611689661
从读写的时间上可以看出读写的操作时互斥的