接上篇:Java多线程技术三:锁的使用——使用ReentrantLock类-1
公平锁采用先到先得的策略,每次获取锁之前都会检查队列里面有没有排队等待的线程,如果没有才会尝试获取锁,如果有就将当前线程追加到队列中。
非公平锁采用“有机会插队”的策略,一个线程获取锁之前,要先去尝试获取锁,而不是在队列中等待,如果成功获取锁,说明线程虽然是后启动的,但先获得了锁,这就是“插队”效果,如果获取锁没有成功,那么将自己追加到队列中进行等待。
public class MyService {
public Lock lock;
public MyService(boolean fair){
lock = new ReentrantLock();
}
public void testMethod(){
try {
lock.lock();
System.out.println("testMethod 方法的线程名 = " + Thread.currentThread().getName());
Thread.sleep(500);
}catch (InterruptedException e){
e.printStackTrace();
}finally {
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 Run1 {
public static void main(String[] args) throws InterruptedException {
MyService service = new MyService(true);
MyThread[] arr1 = new MyThread[10];
MyThread[] arr2 = new MyThread[10];
for (int i = 0; i < arr1.length; i++) {
arr1[i] = new MyThread(service);
arr1[i].setName("arr1+++"+(i+1));
}
for (int i = 0; i < arr1.length; i++) {
arr1[i].start();
}
for (int i = 0; i < arr2.length; i++) {
arr2[i] = new MyThread(service);
arr2[i].setName("arr2---"+(i+1));
}
Thread.sleep(500);
for (int i = 0; i < arr2.length; i++) {
arr2[i].start();
}
}
}
打印的结果是arr1+++在前,arr2---在后,说明arr2---没有任何机会抢到锁,这就是公平锁的特点。
下面创建非公平锁测试的运行类
public class Run2 {
public static void main(String[] args) throws InterruptedException {
MyService service = new MyService(false);
MyThread[] arr1 = new MyThread[20];
MyThread[] arr2 = new MyThread[20];
for (int i = 0; i < arr1.length; i++) {
arr1[i] = new MyThread(service);
arr1[i].setName("arr1+++"+(i+1));
}
for (int i = 0; i < arr1.length; i++) {
arr1[i].start();
}
for (int i = 0; i < arr2.length; i++) {
arr2[i] = new MyThread(service);
arr2[i].setName("arr2---"+(i+1));
}
Thread.sleep(500);
for (int i = 0; i < arr2.length; i++) {
arr2[i].start();
}
}
}
在多次运行程序后,使用非公平锁又看见额能在第2次arr2---,说明启动的线程先抢到锁,这就是非公平锁的特点。
public int getHoldCount()方法的作用是查询“当前线程”保持此锁定的个数,也就是调用lock()方法的次数。
public class MyService {
private ReentrantLock lock = new ReentrantLock(true);
public void testMethod1(){
System.out.println("A" + lock.getHoldCount());
lock.lock();
System.out.println("B" + lock.getHoldCount());
testMethod2();
System.out.println("F" + lock.getHoldCount());
lock.unlock();
System.out.println("G" + lock.getHoldCount());
}
public void testMethod2(){
System.out.println("C" + lock.getHoldCount());
lock.lock();
System.out.println("D" + lock.getHoldCount());
lock.unlock();
System.out.println("E" + lock.getHoldCount());
}
}
public class Run1 {
public static void main(String[] args) {
MyService service = new MyService();
service.testMethod1();
}
}
执行lock方法进行锁重入,导致count计数加1的效果,执行unlock方法会使count呈减1的效果。
public final int getQueueLength()方法 的作用是返回正等待获取此锁线程的估计数,比如有5个线程,1个线程长时间占有锁,那么在调用getQueueLength()方法后的返回值是4,说明有4个线程同时在等待锁的释放。
public class Service {
public ReentrantLock lock = new ReentrantLock();
public void serviceMethod1(){
try {
lock.lock();
System.out.println("ThreadName = " +Thread.currentThread().getName());
Thread.sleep(Integer.MAX_VALUE);
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
public class Run1 {
public static void main(String[] args) throws InterruptedException {
final Service service = new Service();
Runnable runnable = new Runnable() {
@Override
public void run() {
service.serviceMethod1();
}
};
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(runnable);
}
for (int i = 0; i < 10; i++) {
threads[i].start();
}
Thread.sleep(2000);
System.out.println("有线程数 :" + service.lock.getQueueLength() + "在等待获取锁");
}
}
public int getWaitQueueLength(Condition condition)方法的所用是返回等待与此锁相关的给定条件Condition的线程估计数,比如有5个线程,每个线程都执行了同一个Condition对象的await方法,则调用getWaitQueueLength方法的返回值是5。
public class Service {
private ReentrantLock lock = new ReentrantLock();
private Condition newCondition = lock.newCondition();
public void waitMethod(){
try {
lock.lock();
newCondition.await();
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void notifyMethod(){
try {
lock.lock();
System.out.println("有"+lock.getWaitQueueLength(newCondition) + "个线程正在等待newCondition");
newCondition.signal();
}finally {
lock.unlock();
}
}
}
public class Run1 {
public static void main(String[] args) throws InterruptedException {
final Service service = new Service();
Runnable runnable = new Runnable() {
@Override
public void run() {
service.waitMethod();
}
};
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(runnable);
}
for (int i = 0; i < 10; i++) {
threads[i].start();
}
Thread.sleep(2000);
service.notifyMethod();
}
}
public final boolean hasQueueThread(Thread thread)方法的作用是查询指定的线程是否正在等待获取此锁,也就是判断参数中的线程是否在等待队列中。
public class Service {
public ReentrantLock lock = new ReentrantLock();
public Condition condition = lock.newCondition();
public void waitMethod(){
try {
lock.lock();
Thread.sleep(Integer.MAX_VALUE);
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
public class Run1 {
public static void main(String[] args) throws InterruptedException {
final Service service = new Service();
Runnable runnable = new Runnable() {
@Override
public void run() {
service.waitMethod();
}
};
Thread a = new Thread(runnable);
a.start();
Thread.sleep(500);
Thread b = new Thread(runnable);
b.start();
Thread.sleep(500);
System.out.println(service.lock.hasQueuedThread(a));
System.out.println(service.lock.hasQueuedThread(b));
}
}
public boolean isLocked()方法的作用是查询此锁定是否由任意线程持有。
public class Service {
private ReentrantLock lock = new ReentrantLock();
public void serviceMethod(){
try {
System.out.println(lock.isLocked());
lock.lock();
System.out.println(lock.isLocked());
}finally {
lock.unlock();
}
}
}
public class Run1 {
public static void main(String[] args) {
final Service service = new Service();
Runnable runnable = new Runnable() {
@Override
public void run() {
service.serviceMethod();
}
};
Thread thread = new Thread(runnable);
thread.start();
}
}
public void lockInterruptibly()方法的作用是当某个线程尝试获得锁并且阻塞在lock-Interruptibly()方法时,该线程可以被中断。
public class MyService {
private ReentrantLock lock = new ReentrantLock();
public void testMethod() throws InterruptedException {
lock.lockInterruptibly();
System.out.println("开始执行 testMethod方法,线程名= " + Thread.currentThread().getName()+ ";执行时间 = " + Utils.data(System.currentTimeMillis()));
for (int i = 0; i < Integer.MAX_VALUE / 10; i++) {
String s = new String();
Math.random();
Thread.currentThread().yield();
}
System.out.println("执行完毕 testMethod方法,线程名=" + Thread.currentThread().getName()+ ";执行时间 = " + Utils.data(System.currentTimeMillis()));
lock.unlock();
}
}
public class ThreadA extends Thread{
private MyService service;
public ThreadA(MyService service) {
this.service = service;
}
@Override
public void run(){
try {
service.testMethod();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public class Run1 {
public static void main(String[] args) throws InterruptedException {
MyService service = new MyService();
ThreadA a = new ThreadA(service);
a.setName("A");
a.start();
Thread.sleep(500);
ThreadA b = new ThreadA(service);
b.setName("B");
b.start();
Thread.sleep(500);
b.interrupt();
System.out.println("main中断b,但并没有成功");
}
}
public boolean tryLock()方法的作用是嗅探拿锁,如果当前线程发现锁被其他线程持有了,则返回false,那么程序继续执行后面的代码,而不是呈阻塞等待锁的状态。
public class MyService {
public ReentrantLock lock = new ReentrantLock();
public void waitMethod(){
if(lock.tryLock()){
System.out.println(Thread.currentThread().getName() + "获得锁");
}else {
System.out.println(Thread.currentThread().getName() + "没有获得锁");
}
}
}
public class Run1 {
public static void main(String[] args) {
final MyService service = new MyService();
Runnable runnable = new Runnable() {
@Override
public void run() {
service.waitMethod();
}
};
Thread a = new Thread(runnable);
a.setName("A");
a.start();
Thread b = new Thread(runnable);
b.setName("B");
b.start();
}
}
public class MyService {
private ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
volatile private int nextWhoPrint = 1;
public void testMethod1(){
try {
lock.lock();
while(nextWhoPrint != 1){
condition.await();
}
System.out.println("AAA");
nextWhoPrint = 2;
condition.signalAll();
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void testMethod2(){
try {
lock.lock();
while(nextWhoPrint != 2){
condition.await();
}
System.out.println(" BBB");
nextWhoPrint = 3;
condition.signalAll();
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void testMethod3(){
try {
lock.lock();
while(nextWhoPrint != 3){
condition.await();
}
System.out.println(" CCC");
nextWhoPrint = 1;
condition.signalAll();
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
public class ThreadA extends Thread{
private MyService service;
public ThreadA(MyService service) {
this.service = service;
}
@Override
public void run(){
service.testMethod1();
}
}
public class ThreadB extends Thread{
private MyService service;
public ThreadB(MyService service) {
this.service = service;
}
@Override
public void run(){
service.testMethod2();
}
}
public class ThreadC extends Thread{
private MyService service;
public ThreadC(MyService service) {
this.service = service;
}
@Override
public void run(){
service.testMethod3();
}
}
public class Run1 {
public static void main(String[] args) {
MyService service = new MyService();
for (int i = 0; i < 5; i++) {
ThreadA a = new ThreadA(service);
a.start();
ThreadB b = new ThreadB(service);
b.start();
ThreadC c = new ThreadC(service);
c.start();
}
}
}