创建reentrantlock.service包,在包下创建MyService类
package reentrantlock.service;
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 condition = lock.newCondition();
public void await()
{
try {
lock.lock();
System.out.println("await时间为"+System.currentTimeMillis());
condition.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
lock.unlock();
}
}
public void signal()
{
try{
lock.lock();
System.out.println("signal时间为"+System.currentTimeMillis());
condition.signal();
}finally {
lock.unlock();
}
}
}
即使用ReentrantLock的同步锁,并且使用它的Condition对象的一个await/signal方法来实现控制并处理线程的状态,使其进入等待或就绪状态。
分别用MyService对象的await、signal方法进行实现。
创建ReentrantLock.thread包,并在包下创建ThreadA类
package reentrantlock.thread;
import reentrantlock.service.MyService;
public class ThreadA extends Thread{
private MyService myService;
public ThreadA(MyService myService)
{
this.myService = myService;
}
@Override
public void run() {
myService.await();
}
}
即ThreadA线程类通过构造方法给MyService对象赋值,并调用该对象的await方法。
创建reentrantlock.thread包,并在包下创建ThreadB类
package reentrantlock.thread;
import reentrantlock.service.MyService;
public class ThreadB extends Thread{
private MyService myService;
public ThreadB(MyService myService)
{
this.myService = myService;
}
@Override
public void run() {
myService.signal();
}
}
即ThreadB线程类通过构造方法给MyService对象赋值,并调用该对象的signal方法。
创建reentrantlock.test包,并在包下创建Run类
package reentrantlock.test;
import reentrantlock.service.MyService;
import reentrantlock.thread.ThreadA;
import reentrantlock.thread.ThreadB;
public class Run {
public static void main(String[] args) throws InterruptedException {
MyService myService =new MyService();
ThreadA threadA = new ThreadA(myService);
threadA.start();
Thread.sleep(3000);
ThreadB threadB = new ThreadB(myService);
threadB.start();
}
}
即通过ThreadA 调用MyService 的await方法,主线程休眠3秒后,ThreadB 调用MyService 的signal方法。
await()方法通过调用Unsafe.park方法使线程暂停运行。
如果传入true,则第二个参数单位时间为毫秒,此时第二个单位时间为绝对时间
//获取Unsafe类的theUnsafe属性
Field f = Unsafe.class.getDeclaredField("theUnsafe");
//给theUnsafe设置为可使用
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
System.out.println("begin"+System.currentTimeMillis());
unsafe.park(true,System.currentTimeMillis()+3000);
System.out.println("end"+System.currentTimeMillis());
如果传入false,则第二个参数单位时间为纳秒,此时为相对时间
//获取Unsafe类的theUnsafe属性
Field f = Unsafe.class.getDeclaredField("theUnsafe");
//给theUnsafe设置为可使用
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
System.out.println("begin"+System.currentTimeMillis());
unsafe.park(false,3000000000L);
System.out.println("end"+System.currentTimeMillis());
signal()方法通过调用Unsafe.unpark方法唤醒线程。
package reentrantlock.thread;
import sun.misc.Unsafe;
public class MyThread extends Thread{
private Unsafe unsafe;
private Thread mainThread;
public MyThread(Unsafe unsafe, Thread mainThread) {
this.unsafe = unsafe;
this.mainThread = mainThread;
}
@Override
public void run() {
try {
Thread.sleep(6000);
unsafe.unpark(mainThread);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
package reentrantlock.test;
import reentrantlock.thread.MyThread;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class Test2 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InterruptedException {
//获取Unsafe类的theUnsafe属性
Field f = Unsafe.class.getDeclaredField("theUnsafe");
//给theUnsafe设置为可使用
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
MyThread myThread = new MyThread(unsafe, Thread.currentThread());
//MyThread线程启动休眠6s,再调用unpark方法
myThread.start();
//main线程休眠0.2秒
Thread.sleep(200);
//开始打印时间为myThread休眠的200毫秒后,所以从begin到end的时间未5.8秒。
System.out.println("begin"+System.currentTimeMillis());
unsafe.park(false,0L);
System.out.println("end"+System.currentTimeMillis());
}
}
创建reentrantlock.service包,然后创建MyService3类
package reentrantlock.service;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MyService3 {
private Lock lock =new ReentrantLock();
public 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.signalAll();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
lock.unlock();
}
}
public void get()
{
try{
lock.lock();
while(hasValue==false)
{
condition.await();
}
System.out.println("消费");
hasValue=false;
condition.signalAll();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
lock.unlock();
}
}
}
即跟之前的wait/notifyAll机制的多对多一样,而ReentrantLock的多对多实现也是使用While来判断条件,使用Condition对象的signalAll方法来唤醒所有等待线程
创建reentrantlock.thread包,然后创建ThreadA3类
package reentrantlock.thread;
import reentrantlock.service.MyService3;
public class ThreadA3 extends Thread{
private MyService3 myService;
public ThreadA3(MyService3 myService)
{
this.myService = myService;
}
@Override
public void run() {
myService.set();
}
}
创建reentrantlock.thread包,然后创建ThreadB3类
package reentrantlock.thread;
import reentrantlock.service.MyService3;
public class ThreadB3 extends Thread{
private MyService3 myService;
public ThreadB3(MyService3 myService)
{
this.myService = myService;
}
@Override
public void run() {
myService.get();
}
}
创建reentrantlock.test包,然后创建Run3类
package reentrantlock.test;
import reentrantlock.service.MyService3;
import reentrantlock.thread.ThreadA3;
import reentrantlock.thread.ThreadB3;
public class Run3 {
public static void main(String[] args) {
MyService3 service = new MyService3();
ThreadA3[] A = new ThreadA3[10];
ThreadB3[] B = new ThreadB3[10];
for (int i = 0; i < 10; i++) {
A[i] = new ThreadA3(service);
B[i] = new ThreadB3(service);
A[i].start();
B[i].start();
}
}
}
即分别创建10个ThreadA3和ThreadB3实例分别调用MyService3实例中的set和get方法。set则是生产操作,get则是消费操作。从而实现多对多。
创建reentrantlock.service包,在包下创建MyService4 类
package reentrantlock.service;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MyService4 {
public Lock lock;
public MyService4(boolean fair)
{
lock = new ReentrantLock(fair);
}
public void testMethod()
{
try {
lock.lock();
System.out.println("testMethod"+Thread.currentThread().getName());
//此处的10ms用于配合 array2有更多可能在非公平的情况下找到锁
//如果线程数量够多,也可以不休眠或让休眠时间更小
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally{
lock.unlock();
}
}
}
即通过MyService4的构造方法给ReentrantLock传参,生成非公平锁对象。
休眠是为了让其他线程有机会抢到锁对象。
创建reentrantlock.thread包,在包下创建MyThread2 类
package reentrantlock.thread;
import reentrantlock.service.MyService4;
public class MyThread2 extends Thread{
private MyService4 service4;
public MyThread2(MyService4 service4)
{
super();
this.service4 = service4;
}
@Override
public void run() {
service4.testMethod();
}
}
即线程类用来调用MyService4的testMethod方法。
创建reentrantlock.test包,在包下创建Run4类
package reentrantlock.test;
import reentrantlock.service.MyService4;
import reentrantlock.thread.MyThread2;
public class Run4 {
public static void main(String[] args) throws InterruptedException {
//即通过MyService4的构造方法将bool值传入,再给ReentrantLock传入,生成非公平锁NonfairSync。
MyService4 myService4 = new MyService4(false);
MyThread2[] array1 = new MyThread2[1000];
MyThread2[] array2 = new MyThread2[1000];
long begin = System.currentTimeMillis();
for (int i = 0; i < array1.length; i++) {
array1[i]= new MyThread2(myService4);
array1[i].setName("array1+++"+(i+1));
array1[i].start();
}
Thread.sleep(10);
for (int i = 0; i < array2.length; i++) {
array2[i]= new MyThread2(myService4);
array2[i].setName("array2---"+(i+1));
array2[i].start();
}
}
}
即通过MyService4的构造方法生成一个非公平锁,生成两个线程数组,使用for循环去启动线程,线程组1和线程组2中间的休眠是为了让线程组1先排队,而线程执行期间休眠是为了让线程组2可以在线程运行时,线程组1刚刚释放锁,线程组二有机会可以抢到线程组1刚刚释放的锁,如果线程量够大,线程执行时的休眠可以不要。
非公平锁运行结果:

而公平锁就是将MyService4构造方法传入的值修改为true,它是按申请锁资源的顺序来给锁资源的。
即上述结果中2不会在1之前。
public int getHoldCount()方法,作用是查询"当前线程"保持此锁的个数,也就是调用lock方法的次数。
执行lock方法进行锁重入,导致count+1,而unlock方法导致count-1。
public final int getQueueLength方法,作用是返回正等待获取此锁的线程的估计数。
public int getWaitQueueLength(Condition condition)方法,作用是返回等待此锁相关的给定条件Condition的线程估计数。即返回调用过condition.await方法的线程估计数。
public final boolean hasQueuedThread(Thread thread),作用是查询指定的线程是否正在等待获取此锁,即判断参数中的线程是否在等待队列中。
public final boolean hasQueuedThreads(),作用是查询是否有线程正在等待获取此锁,即等待队列中是否有等待的线程。
public boolean hasWaiters(Condition condition),作用是查询是否有线程正在等待与此锁有关的condition对象,即是否有线程执行了condition对象的await方法而呈等待状态。
public final boolean isFair(),作用是判断是不是公平锁。
ReentrantLock默认是非公平锁。
public boolean isHeldByCurrentThread(),作用是查询当前线程是否持有此锁。
public boolean isLocked(),作用是查询此锁是否有线程持有,并且未释放。
public void lockInterruptibly(),作用是当某个线程尝试获得锁并且阻塞在lockInterruptibly()方法时,该线程可以被中断。
即使用lockInterruptibly方法进行加锁时,该锁可以被中断(interrupt)。
public boolean tryLock(),作用是当前线程发现锁被其他线程持有了,则返回false,那么程序继续执行后面的代码,而不是呈阻塞等待锁状态的。
即可以将tryLock作为一个判断条件,true(获得锁)则执行true指定的语句,false执行false指定的语句。
public boolean tryLock(long timeout,TimeUnit unit),如果在指定的timeout时间内持有了锁,则返回true,如果超过时间则返回false。
public boolean await(long time,TimeUnit unit)和public final native void wait(long timeout)方法一样,具有自动唤醒功能。
public long awaitNanos(long nanosTimeout),具有自动唤醒功能,时间单位是纳秒。
1000纳秒=1微秒,1000微秒=1毫秒,1000毫秒=1秒。
public boolean awaitUntil(Date deadline),作用是在指定的日期结束等待。
13-15的方法都是具有自动唤醒功能的等待方法。
public void awaitUninterruptibly(),作用是等待的过程中,不允许被中断。即将await方法换成awaitUninterruptibly方法。
使用ReentrantLock对象时,对所有的操作都同步,包括读取操作,这样会耗费大量时间,降低运行效率。
创建一个reentrantreadwritelock.service包,在包下创建MyService 类
package reentrantreadwritelock.service;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class MyService {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private String username = "abc";
public void testMethod()
{
try {
lock.readLock().lock();
System.out.println("begin "+Thread.currentThread().getName()+ System.currentTimeMillis());
System.out.println("print service"+ username);
Thread.sleep(4000);
System.out.println("end "+Thread.currentThread().getName()+""+System.currentTimeMillis());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
lock.readLock().unlock();
}
}
}
创建一个reentrantreadwritelock.thread包,在包下创建ThreadA类
package reentrantreadwritelock.thread;
import reentrantreadwritelock.service.MyService;
public class ThreadA extends Thread{
private MyService myService = new MyService();
public ThreadA(MyService myService)
{
this.myService = myService;
}
@Override
public void run() {
myService.testMethod();
}
}
创建一个reentrantreadwritelock.thread包,在包下创建ThreadB类
package reentrantreadwritelock.thread;
import reentrantreadwritelock.service.MyService;
public class ThreadB extends Thread{
private MyService myService = new MyService();
public ThreadB(MyService myService)
{
this.myService = myService;
}
@Override
public void run() {
myService.testMethod();
}
}
创建一个reentrantreadwritelock.thread包,在包下创建ThreadB类
package reentrantreadwritelock.test;
import reentrantreadwritelock.service.MyService;
import reentrantreadwritelock.thread.ThreadA;
import reentrantreadwritelock.thread.ThreadB;
public class Run {
public static void main(String[] args) {
MyService myService =new MyService();
ThreadA a = new ThreadA(myService);
a.setName("a");
a.start();
ThreadB b = new ThreadB(myService);
b.setName("b");
b.start();
}
}
即创建一个MyService 实例,将其传入ThreadA和ThreadB实例中,两个线程共用一把锁。读锁是共享锁,所以两个读操作不会互斥,可以同时进行读操作,减少同步耗费的时间。
创建一个reentrantreadwritelock.service包,在包下创建MyService2 类
package reentrantreadwritelock.service;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class MyService2 {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private String username = "abc";
public void write()
{
try {
lock.writeLock().lock();
System.out.println("获得写锁 "+Thread.currentThread().getName()+ System.currentTimeMillis());
Thread.sleep(10000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
lock.writeLock().unlock();
}
}
}
创建一个reentrantreadwritelock.thread包,在包下创建ThreadA2 类
package reentrantreadwritelock.thread;
import reentrantreadwritelock.service.MyService2;
public class ThreadA2 extends Thread{
private MyService2 myService = new MyService2();
public ThreadA2(MyService2 myService)
{
this.myService = myService;
}
@Override
public void run() {
myService.write();
}
}
创建一个reentrantreadwritelock.thread包,在包下创建ThreadB2 类
package reentrantreadwritelock.thread;
import reentrantreadwritelock.service.MyService2;
public class ThreadB2 extends Thread{
private MyService2 myService = new MyService2();
public ThreadB2(MyService2 myService)
{
this.myService = myService;
}
@Override
public void run() {
myService.write();
}
}
创建一个reentrantreadwritelock.test包,在包下创建Run2 类
package reentrantreadwritelock.test;
import reentrantreadwritelock.service.MyService2;
import reentrantreadwritelock.thread.ThreadA2;
import reentrantreadwritelock.thread.ThreadB2;
public class Run2 {
public static void main(String[] args) {
MyService2 myService =new MyService2();
ThreadA2 a = new ThreadA2(myService);
a.setName("a");
a.start();
ThreadB2 b = new ThreadB2(myService);
b.setName("b");
b.start();
}
}
即创建一个MyService2实例,2个线程传入同一个MyService2实例,线程调用MyService2同一个方法,该方法使用写锁,此时写写互斥,需要等第一个线程执行方法结束后,第二个线程才能执行方法内的任务。
创建一个reentrantreadwritelock.service包,在包下创建MyService3 类
package reentrantreadwritelock.service;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class MyService3 {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void read()
{
try {
lock.readLock().lock();
System.out.println("获得读锁"+Thread.currentThread().getName()+System.currentTimeMillis());
Thread.sleep(10000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
lock.readLock().unlock();
}
}
public void write()
{
try {
lock.writeLock().lock();
System.out.println("获得写锁"+Thread.currentThread().getName()+System.currentTimeMillis());
Thread.sleep(10000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
lock.writeLock().unlock();
}
}
}
创建一个reentrantreadwritelock.thread包,在包下创建ThreadA3 类
package reentrantreadwritelock.thread;
import reentrantreadwritelock.service.MyService3;
public class ThreadA3 extends Thread{
private MyService3 myService = new MyService3();
public ThreadA3(MyService3 myService)
{
this.myService = myService;
}
@Override
public void run() {
myService.read();
}
}
创建一个reentrantreadwritelock.thread包,在包下创建ThreadB3 类
package reentrantreadwritelock.thread;
import reentrantreadwritelock.service.MyService3;
public class ThreadB3 extends Thread{
private MyService3 myService = new MyService3();
public ThreadB3(MyService3 myService)
{
this.myService = myService;
}
@Override
public void run() {
myService.write();
}
}
创建一个reentrantreadwritelock.test包,在包下创建Run3 类
package reentrantreadwritelock.test;
import reentrantreadwritelock.service.MyService3;
import reentrantreadwritelock.thread.ThreadA3;
import reentrantreadwritelock.thread.ThreadB3;
public class Run3 {
public static void main(String[] args) {
MyService3 myService =new MyService3();
ThreadA3 a = new ThreadA3(myService);
a.setName("a");
a.start();
ThreadB3 b = new ThreadB3(myService);
b.setName("b");
b.start();
}
}
即创建一个MyService3实例,2个线程传入同一个MyService3实例,线程A调用MyService3的read方法,线程B调用MyService3的write方法,此时读写互斥,需要等第一个线程执行读方法结束后,第二个线程才能执行写方法内的任务。
即跟读写互斥相同,线程AB调用的方法互换即可。