ReentrantLock学习
1、基本的使用,synchronized对象锁:
测试1:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public 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();
}
}
public class MyThread extends Thread {
private MyService service;
public MyThread(MyService service){
this.service=service;
}
@Override
public void run(){
service.testMethod();
}
}
public class test {
public static void main(String args[]){
MyService service=new MyService();
MyThread a1=new MyThread(service);
MyThread a2=new MyThread(service);
MyThread a3=new MyThread(service);
MyThread a4=new MyThread(service);
MyThread a5=new MyThread(service);
a1.start();
a2.start();
a3.start();
a4.start();
a5.start();
}
}
运行输出:
ThreadName=Thread-0 1
ThreadName=Thread-0 2
ThreadName=Thread-0 3
ThreadName=Thread-0 4
ThreadName=Thread-0 5
ThreadName=Thread-1 1
ThreadName=Thread-1 2
ThreadName=Thread-1 3
ThreadName=Thread-1 4
ThreadName=Thread-1 5
ThreadName=Thread-2 1
ThreadName=Thread-2 2
ThreadName=Thread-2 3
ThreadName=Thread-2 4
ThreadName=Thread-2 5
ThreadName=Thread-4 1
ThreadName=Thread-4 2
ThreadName=Thread-4 3
ThreadName=Thread-4 4
ThreadName=Thread-4 5
ThreadName=Thread-3 1
ThreadName=Thread-3 2
ThreadName=Thread-3 3
ThreadName=Thread-3 4
ThreadName=Thread-3 5
Process finished with exit code 0
测试2:
public class MyService {
private Lock lock=new ReentrantLock();
public void methodA(){
try{
lock.lock();
System.out.println("methodA begin ThreadName="+Thread.currentThread()
+" time="+System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("methodA end ThreadName="+Thread.currentThread()
+" time="+System.currentTimeMillis());
}catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void methodB(){
try{
lock.lock();
System.out.println("methodB begin ThreadName="+Thread.currentThread()
+" time="+System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("methodB end ThreadName="+Thread.currentThread()
+" time="+System.currentTimeMillis());
}catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
public class ThreadA extends Thread {
private MyService service;
public ThreadA(MyService service){
super();
this.service=service;
}
@Override
public void run(){
service.methodA();
}
}
public class ThreadAA extends Thread {
private MyService service;
public ThreadAA(MyService service){
super();
this.service=service;
}
@Override
public void run(){
service.methodA();
}
}
public class ThreadB extends Thread {
private MyService service;
public ThreadB(MyService service){
super();
this.service=service;
}
@Override
public void run(){
service.methodB();
}
}
public class ThreadBB extends Thread {
private MyService service;
public ThreadBB(MyService service){
super();
this.service=service;
}
@Override
public void run(){
service.methodB();
}
}
public class test {
public static void main(String args[]){
MyService service=new MyService();
ThreadA a=new ThreadA(service);
a.setName("A");
ThreadAA aa=new ThreadAA(service);
aa.setName("AA");
ThreadB b=new ThreadB(service);
b.setName("B");
ThreadBB bb=new ThreadBB(service);
bb.setName("BB");
a.start();
aa.start();
b.start();
bb.start();
}
}
结果:
methodA begin ThreadName=Thread[AA,5,main] time=1534741677491
methodA end ThreadName=Thread[AA,5,main] time=1534741682492
methodA begin ThreadName=Thread[A,5,main] time=1534741682492
methodA end ThreadName=Thread[A,5,main] time=1534741687493
methodB begin ThreadName=Thread[B,5,main] time=1534741687493
methodB end ThreadName=Thread[B,5,main] time=1534741692493
methodB begin ThreadName=Thread[BB,5,main] time=1534741692493
methodB end ThreadName=Thread[BB,5,main] time=1534741697493
通过两测试可以发现,lock可以实现与synchronized一样的效果,那么lock与reentrantlock的差异在那里呢,我们继续看:
要注意synchronized同步,假如发生异常,JVM是可以帮我们自动释放锁的,但是lock不可以,我们只能手动释放锁,即使发生异常,jvm也不会自动释放锁。
首先我们知道synchronized与wait()和notify()/notifyAll()方法结合可以实现等待通知模式,Reentrantlock可以实现同样的宫鞥你,在synchronized当中,被通知的线程是由JVM随机选择,但是lock结合condition可以实现选择性通知。
注意在condition.await()方法调用之前,必须先lock.lock()获得锁。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MyService {
private Lock lock=new ReentrantLock();
public Condition conditionA=lock.newCondition();
public 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();
}
}
public void signalAll_A(){
try {
lock.lock();
System.out.println("signalAll_A时间为"+System.currentTimeMillis()
+"ThreadName"+ Thread.currentThread().getName());
conditionA.signalAll();
}finally {
lock.unlock();
}
}
public void signalAll_B(){
try {
lock.lock();
System.out.println("signalAll_B时间为"+System.currentTimeMillis()
+"ThreadName"+ Thread.currentThread().getName());
conditionB.signalAll();
}finally {
lock.unlock();
}
}
}
public class ThreadA extends Thread {
private MyService service;
public ThreadA(MyService service){
super();
this.service=service;
}
@Override
public void run(){
service.awaitA();
}
}
public class ThreadB extends Thread {
private MyService service;
public ThreadB(MyService service){
super();
this.service=service;
}
@Override
public void run(){
service.awaitB();
}
}
public class test {
public static void main(String args[]){
MyService service=new MyService();
ThreadA a=new ThreadA(service);
a.setName("A");
ThreadB b=new ThreadB(service);
b.setName("B");
a.start();
b.start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
service.signalAll_A();
}
}
输出:
begin awaitA时间为1534744090922ThreadName=A
begin awaitB时间为1534744090922ThreadName=B
signalAll_A时间为1534744093922ThreadNamemain
end awaitA 时间为1534744093922ThreadNameA
可以看到只有A被唤醒
synchronized的join()方法是为了让别的线程执行完在执行下面的语句
如
ThreadA a=new ThreadA();
a.start();
a.join();
//希望a执行完之后再执行语句
...........
join(long)是设置等待的时间
join(long)与sleep(long)的区别,join(long)在等待的时候释放锁,而sleep不会。
InheritableThreadLocal可以让子线程从父线程中取得值。
继承InheritableThreadLocal重写intialValue()方法
继承InheritableThreadLocal重写intialValue()与childValue()方法
ReentrantReadWriteLock的使用:读读共享,写写互斥,读写互斥
自旋锁也叫不可重入锁
//可重入锁的基本原理:
public class Lock{
boolean isLocked = false;
Thread lockedBy = null; //记录已经获得锁的线程
int lockedCount = 0;//记录加锁数量
public synchronized void lock() throws InterruptedException{
Thread callingThread = Thread.currentThread();
while(isLocked && lockedBy != callingThread){
//如果被锁并且当前线程是不是获得锁的线程,那么等待
wait();
}
isLocked = true;
lockedCount++;
lockedBy = callingThread;
}
public synchronized void unlock(){
if(Thread.curentThread() == this.lockedBy){
//如果当前线程是之前获得锁的线程
lockedCount--;
if(lockedCount == 0){
isLocked = false;
notify();
}
}
}
}