Java多线程编程(四)Lock的使用

  一、使用ReentrantLock类

  在Java多线程中,可以使用synchronized关键字来实现线程之间的同步互斥,但ReentrantLock类也能达到同样的效果,并且在扩展功能上也更加强大,比如具有嗅探锁定、多路分支通知等功能,而且在使用上也比synchronized更加的灵活。

  1.使用ReentrantLock实现同步:测试1

  示例:从运行的结果来看,是同步运行的,即当前线程打印完毕之后将锁进行释放,其他线程才可以继续打印。线程打印的数据是分组打印的,因为当前线程已经持有锁,但线程之间打印的顺序是随机的。

package service;

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();
    }

}
package extthread;

import service.MyService;

public class MyThread extends Thread {

    private MyService service;

    public MyThread(MyService service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.testMethod();
    }
}
package test;

import service.MyService;
import extthread.MyThread;

public class Run {

    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-2 1
ThreadName=Thread-2 2
ThreadName=Thread-2 3
ThreadName=Thread-2 4
ThreadName=Thread-2 5
ThreadName=Thread-1 1
ThreadName=Thread-1 2
ThreadName=Thread-1 3
ThreadName=Thread-1 4
ThreadName=Thread-1 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

  2.使用ReentrantLock实现同步:测试2

  示例:线程A和AA为一组,执行方法a,线程B和BB为一组,执行方法b。从结果可以看出,调用lock.lock();代码的线程就持有了“对象监视器”,其他线程只有等待锁被释放时再次争抢。效果和使用synchronized一样,线程之间还是顺序执行的。

package extthread;

import service.MyService;

public class ThreadA extends Thread {

    private MyService service;

    public ThreadA(MyService service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.methodA();
    }
}
package service;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {

    private Lock lock = new ReentrantLock();

    public void methodA() {
        try {
            lock.lock();
            System.out.println("methodA begin ThreadName="+ Thread.currentThread().getName() 
                             + " time="+ System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("methodA  end ThreadName="+ Thread.currentThread().getName() 
                             + " 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().getName() 
                             + " time="+ System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("methodB  end ThreadName="+ Thread.currentThread().getName() 
                             + " time="+ System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}
package test;

import service.MyService;
import extthread.ThreadA;
import extthread.ThreadAA;
import extthread.ThreadB;
import extthread.ThreadBB;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        MyService service = new MyService();

        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();
        
        ThreadAA aa = new ThreadAA(service);
        aa.setName("AA");
        aa.start();

        Thread.sleep(100);

        ThreadB b = new ThreadB(service);
        b.setName("B");
        b.start();
        
        ThreadBB bb = new ThreadBB(service);
        bb.setName("BB");
        bb.start();

    }

}
methodA begin ThreadName=A time=1525674628430
methodA  end ThreadName=A time=1525674633431
methodA begin ThreadName=AA time=1525674633432
methodA  end ThreadName=AA time=1525674638436
methodB begin ThreadName=B time=1525674638436
methodB  end ThreadName=B time=1525674643443
methodB begin ThreadName=BB time=1525674643443
methodB  end ThreadName=BB time=1525674648443

  3.使用Condition实现等待/通知错误用法与解决

  Condition类可以用来实现多路通知功能,也就是在一个Lock对象里面可以创建多个Condition实例,线程对象可以注册在指定的Condition中,从而可以有选择性地进行线程通知,在调度线程上更加灵活。synchronized就相当于整个Lock对象中只有一个单一的Condition对象,所有的线程都注册在它一个对象的身上。

  示例1:出现异常的原因是监视器出错,解决的办法是必须在condition.await()方法调用之前调用lock.lock()代码取得同步监视器。

package 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();
    private Condition condition = lock.newCondition();

    public void await() {
        try {
            condition.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package extthread;

import service.MyService;

public class ThreadA extends Thread {

    private MyService service;

    public ThreadA(MyService service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.await();
    }
}
package test;

import service.MyService;
import extthread.ThreadA;

public class Run {

    public static void main(String[] args) {

        MyService service = new MyService();

        ThreadA a = new ThreadA(service);
        a.start();

    }

}
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
	at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(Unknown Source)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(Unknown Source)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.fullyRelease(Unknown Source)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(Unknown Source)
	at service.MyService.await(MyService.java:14)
	at extthread.ThreadA.run(ThreadA.java:16)

   示例2:修改await()方法,输出只打印了一个A,说明了condition.await();方法使当前执行任务的线程进入了等待状态,在lock.unlock();释放锁后才可以继续执行。

package service;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {
    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void waitMethod() {
        try {
            lock.lock();
            System.out.println("A");
            condition.await();
            System.out.println("B");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
            System.out.println("锁被释放了!");
        }
    }
}
A

  4.正确使用Condition实现等待/通知

  示例:从输出结果可以看出,使用condition.await();condition.signal();成功实现了等待/通知模式。

  和之前的wait/notify做对比:

  Object类中的wait()方法--------Condition类中的await()方法

  Object类中的wait(long)方法--Condition类中的await(long)方法

  Object类中的notify()方法-------Condition类中的signal()方法

  Object类中的notifyAll()方法---Condition类中的signalAll()方法

package 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) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void signal() {
        try {
            lock.lock();
            System.out.println("signal打印时间:" + System.currentTimeMillis());
            condition.signal();
        } finally {
            lock.unlock();
        }
    }
}
package extthread;

import service.MyService;

public class ThreadA extends Thread {

    private MyService service;

    public ThreadA(MyService service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.await();
    }
}
package test;

import service.MyService;
import extthread.ThreadA;

public class Run {

    public static void main(String[] args) throws InterruptedException {

        MyService service = new MyService();

        ThreadA a = new ThreadA(service);
        a.start();

        Thread.sleep(3000);

        service.signal();

    }

}
 await打印时间:1525675563292
signal打印时间:1525675566292

  5.使用多个Condition实现通知部分线程:错误用法

  示例:程序运行后,由于使用了service.signalAll();而signalAll()方法中使用了condition.signalAll();所以使线程A和线程B都被唤醒了,(如果将condition.signalAll();修改成condition.signal();那么只能随机有一个线程被唤醒,通过多次输出发现线程B一直都不会被唤醒。如果想单独唤醒部分线程,就有必要使用多个Condition对象了,也就是Condition对象可以唤醒部分指定线程,有助于提升程序运行的效率。可以先对线程进行分组,然后再唤醒执行组中的线程。

package 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 awaitA() {
        try {
            lock.lock();
            System.out.println("begin awaitA time" + System.currentTimeMillis()
                    + " ThreadName=" + Thread.currentThread().getName());
            condition.await();
            System.out.println("  end awaitA time" + 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 time" + System.currentTimeMillis()
                    + " ThreadName=" + Thread.currentThread().getName());
            condition.await();
            System.out.println("  end awaitB time" + System.currentTimeMillis()
                    + " ThreadName=" + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void signalAll() {
        try {
            lock.lock();
            System.out.println("  signalAll time" + System.currentTimeMillis()
                    + " ThreadName=" + Thread.currentThread().getName());
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }
}
package extthread;

import service.MyService;

public class ThreadA extends Thread {

    private MyService service;

    public ThreadA(MyService service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.awaitA();
    }
}
package extthread;

import service.MyService;

public class ThreadB extends Thread {

    private MyService service;

    public ThreadB(MyService service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.awaitB();
    }
}
package test;

import service.MyService;
import extthread.ThreadA;
import extthread.ThreadB;

public class Run {

    public static void main(String[] args) throws InterruptedException {

        MyService service = new MyService();

        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();

        ThreadB b = new ThreadB(service);
        b.setName("B");
        b.start();

        Thread.sleep(3000);

        service.signalAll();

    }

}
begin awaitA time1525676214892 ThreadName=A
begin awaitB time1525676214892 ThreadName=B
   signalAll time1525676217896 ThreadName=main
  end awaitA time1525676217896 ThreadName=A
  end awaitB time1525676217896 ThreadName=B

  6.使用多个Condition实现通知部分线程:正确用法

  示例:修改MyService.java创建多个Condition对象,main方法中只唤醒A线程。从输出结果来看,确实只唤醒了一个指定的线程A线程。

package 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 conditionA = lock.newCondition();
    public Condition conditionB = lock.newCondition();

    public void awaitA() {
        try {
            lock.lock();
            System.out.println("begin awaitA time" + System.currentTimeMillis()
                    + " ThreadName=" + Thread.currentThread().getName());
            conditionA.await();
            System.out.println("  end awaitA time" + 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 time" + System.currentTimeMillis()
                    + " ThreadName=" + Thread.currentThread().getName());
            conditionB.await();
            System.out.println("  end awaitB time" + 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 time" + System.currentTimeMillis()
                    + " ThreadName=" + Thread.currentThread().getName());
            conditionA.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public void signalAll_B() {
        try {
            lock.lock();
            System.out.println("  signalAll_B time" + System.currentTimeMillis()
                    + " ThreadName=" + Thread.currentThread().getName());
            conditionB.signalAll();
        } finally {
            lock.unlock();
        }
    }
}
package test;

import service.MyService;
import extthread.ThreadA;
import extthread.ThreadB;

public class Run {

    public static void main(String[] args) throws InterruptedException {

        MyService service = new MyService();

        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();

        ThreadB b = new ThreadB(service);
        b.setName("B");
        b.start();

        Thread.sleep(3000);

        service.signalAll_A();

    }

}
begin awaitA time1525676857516 ThreadName=A
begin awaitB time1525676857516 ThreadName=B
 signalAll_A time1525676860517 ThreadName=main
  end awaitA time1525676860517 ThreadName=A

  7.实现生产者/消费者模式:一对一交替打印

  示例:和前面学习过的wait/notify实现一对一交替打印的原理一样,通过改变hasValue的值来实现。从输出结果可以看出,使用Condition对象成功地实现了交替打印的效果。

package service;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {

    private ReentrantLock 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("打印set");
            hasValue = true;
            condition.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void get() {
        try {
            lock.lock();
            while (hasValue == false) {
                condition.await();
            }
            System.out.println("打印get");
            hasValue = false;
            condition.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}
package extthread;

import service.MyService;

public class MyThreadA extends Thread {

    private MyService myService;

    public MyThreadA(MyService myService) {
        super();
        this.myService = myService;
    }

    @Override
    public void run() {
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            myService.set();
        }
    }

}
package extthread;

import service.MyService;

public class MyThreadB extends Thread {

    private MyService myService;

    public MyThreadB(MyService myService) {
        super();
        this.myService = myService;
    }

    @Override
    public void run() {
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            myService.get();
        }
    }

}
package test;

import service.MyService;
import extthread.MyThreadA;
import extthread.MyThreadB;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        MyService myService = new MyService();

        MyThreadA a = new MyThreadA(myService);
        a.start();

        MyThreadB b = new MyThreadB(myService);
        b.start();

    }
}
打印set
打印get
打印set
打印get
打印set
打印get
打印set
打印get
打印set
打印get
打印set
打印get
打印set
打印get
...

  8.实现生产者/消费者模式:多对多交替打印

  示例1:修改MyService类和Run类。从输出可以看出,程序运行后出现了“假死”,不能一直运行下去,出现的原因和之前的notify()不是notifyAll()一样。

package service;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {

    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    private boolean hasValue = false;

    public void set() {
        try {
            lock.lock();
            while (hasValue == true) {
                System.out.println("hasValue值为true");
                condition.await();
            }
            System.out.println("打印set");
            hasValue = true;
            condition.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void get() {
        try {
            lock.lock();
            while (hasValue == false) {
                System.out.println("hasValue值为false");
                condition.await();
            }
            System.out.println("打印get");
            hasValue = false;
            condition.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}
package test;

import service.MyService;
import extthread.MyThreadA;
import extthread.MyThreadB;

public class Run {

    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();
        }

    }
}
打印set
hasValue值为true
打印get
hasValue值为false
打印set
hasValue值为true
打印get
hasValue值为false
打印set
hasValue值为true
打印get
hasValue值为false
打印set
hasValue值为true
打印get
hasValue值为false
打印set
hasValue值为true
hasValue值为true
打印get
hasValue值为false
hasValue值为false
hasValue值为false
打印set
hasValue值为true
hasValue值为true
hasValue值为true
打印get
hasValue值为false
打印set
hasValue值为true
hasValue值为true
打印get
hasValue值为false
hasValue值为false
打印set
hasValue值为true
打印get
hasValue值为false
hasValue值为false
打印set
hasValue值为true
打印get
hasValue值为false
打印set
hasValue值为true
hasValue值为true
打印get
hasValue值为false
打印set
hasValue值为true
hasValue值为true
hasValue值为true
打印get
hasValue值为false
打印set
hasValue值为true
hasValue值为true
打印get
hasValue值为false
hasValue值为false
hasValue值为false
打印set
hasValue值为true
打印get
hasValue值为false
hasValue值为false
打印set
hasValue值为true
打印get
hasValue值为false
hasValue值为false
打印set
hasValue值为true
打印get
hasValue值为false
打印set
hasValue值为true
hasValue值为true
打印get
hasValue值为false
打印set
hasValue值为true
hasValue值为true
hasValue值为true

   示例2:修改成signalAll()后,程序可以一直运行下去,不再出现“假死”的现象,set和get是交替输出的,但是true和false却不是交替输出的,这是因为程序中使用了同一个Condition对象,在结合signalAll()方法唤醒所有的线程,那么唤醒的线程就有可能是同类,因此就出现了不是交替输出的情况。

打印set
hasValue值为true
hasValue值为true
hasValue值为true
hasValue值为true
打印get
hasValue值为false
hasValue值为false
hasValue值为false
hasValue值为false
hasValue值为false
hasValue值为false
hasValue值为false
hasValue值为false
打印set
hasValue值为true
hasValue值为true
hasValue值为true
hasValue值为true
打印get
hasValue值为false
打印set
hasValue值为true
hasValue值为true
打印get
hasValue值为false
打印set
hasValue值为true
hasValue值为true
hasValue值为true
hasValue值为true
打印get
hasValue值为false
hasValue值为false
hasValue值为false
hasValue值为false
hasValue值为false
hasValue值为false
hasValue值为false
hasValue值为false
...

  9.公平锁与非公平锁

  锁Lock分为“公平锁”和“非公平锁”,公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的FIFO先进先出顺序。而非公平锁就是一种获取锁的抢占机制,是随机获得锁的,和公平锁不一样的就是先来的不一定先得到锁,这个方式可能造成某些线程一直拿不到锁,结果也就是不公平的了。

  示例1:公平锁的测试类。lock = new ReentrantLock(isFair);中isFair设置为true,打印的结果基本是呈有序的状态。

package service;

import java.util.concurrent.locks.ReentrantLock;

public class Service {

    private ReentrantLock lock;

    public Service(boolean isFair) {
        super();
        lock = new ReentrantLock(isFair);
    }

    public void serviceMethod() {
        try {
            lock.lock();
            System.out.println("ThreadName=" + Thread.currentThread().getName()
                    + "获得锁定");
        } finally {
            lock.unlock();
        }
    }

}
package test.run;

import service.Service;

public class RunFair {

    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-0运行了
★线程Thread-1运行了
ThreadName=Thread-0获得锁定
★线程Thread-3运行了
★线程Thread-5运行了
★线程Thread-7运行了
ThreadName=Thread-1获得锁定
★线程Thread-6运行了
ThreadName=Thread-2获得锁定
ThreadName=Thread-3获得锁定
ThreadName=Thread-5获得锁定
★线程Thread-4运行了
ThreadName=Thread-7获得锁定
ThreadName=Thread-6获得锁定
ThreadName=Thread-4获得锁定
★线程Thread-8运行了
ThreadName=Thread-8获得锁定
★线程Thread-9运行了
ThreadName=Thread-9获得锁定

   示例2:非公平锁的测试类。lock = new ReentrantLock(isFair);中isFair设置为false,打印的结果基本是呈乱序的状态,说明先start()启动的线程不代表先获得锁。

package test.run;

import service.Service;

public class RunNotFair {

    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-0运行了
★线程Thread-1运行了
ThreadName=Thread-1获得锁定
ThreadName=Thread-0获得锁定
★线程Thread-2运行了
★线程Thread-3运行了
ThreadName=Thread-3获得锁定
ThreadName=Thread-2获得锁定
★线程Thread-4运行了
★线程Thread-6运行了
ThreadName=Thread-4获得锁定
ThreadName=Thread-6获得锁定
★线程Thread-5运行了
ThreadName=Thread-5获得锁定
★线程Thread-9运行了
★线程Thread-7运行了
★线程Thread-8运行了
ThreadName=Thread-9获得锁定
ThreadName=Thread-7获得锁定
ThreadName=Thread-8获得锁定

  10.方法getHoldCount()、getQueueLength()、getWaitQueueLength()的测试

  示例1:getHoldCount()方法的作用是查询当前线程保持此锁定的个数,也就是调用lock()方法的次数。

package test1;

import java.util.concurrent.locks.ReentrantLock;

public class Service {

    private ReentrantLock lock = new ReentrantLock();

    public void serviceMethod1() {
        try {
            lock.lock();
            System.out.println("serviceMethod1 getHoldCount="+ lock.getHoldCount());
            serviceMethod2();
        } finally {
            lock.unlock();
        }
    }

    public void serviceMethod2() {
        try {
            lock.lock();
            System.out.println("serviceMethod2 getHoldCount="+ lock.getHoldCount());
        } finally {
            lock.unlock();
        }
    }

}
package test1;

public class Run {

    public static void main(String[] args) {
        Service service = new Service();
        service.serviceMethod1();
    }
}
serviceMethod1 getHoldCount=1
serviceMethod2 getHoldCount=2

  示例2:getQueueLength()方法的作用是返回正等待获取此锁定的线程估计数,从输出可以看出,有一个线程进入了方法,由于sleep很久,所以其他九个线程都在等待获取此锁的释放。

package test2;

import java.util.concurrent.locks.ReentrantLock;

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();
        }
    }

}
package test2;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        final Service service = new Service();

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service.serviceMethod1();
            }
        };

        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.sleep(2000);
        System.out.println("有线程数:" + service.lock.getQueueLength() + "在等待获取锁!");

    }
}
ThreadName=Thread-1进入方法!
有线程数:9在等待获取锁!

  示例3:getWaitQueueLength(newCondition)方法的作用是返回等待于此锁定相关的给定条件Condition的线程估计数,示例中10个线程都执行了同一个Condition对象的await()方法,则返回值就是10

package test3;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

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 notityMethod() {
        try {
            lock.lock();
            System.out.println("有" + lock.getWaitQueueLength(newCondition)
                    + "个线程正在等待newCondition");
            newCondition.signal();
        } finally {
            lock.unlock();
        }
    }

}
package test3;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        final Service service = new Service();

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service.waitMethod();
            }
        };

        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.sleep(2000);
        service.notityMethod();
    }
}
有10个线程正在等待newCondition

  11.方法hasQueuedThread()、hasQueuedThreads()、hasWaiters()的测试

  示例1:hasQueuedThread(threadA)的作用是查询指定的线程A是否正在等待获取此锁定,hasQueuedThreads()的作用是查询是否有线程正在等待获取此锁定。示例中线程A获取了此锁定,因此会打印出这种效果。

package test1;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Service {

    public ReentrantLock lock = new ReentrantLock();
    public Condition newCondition = lock.newCondition();

    public void waitMethod() {
        try {
            lock.lock();
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
package test1;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        final Service service = new Service();

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service.waitMethod();
            }
        };

        Thread threadA = new Thread(runnable);
        threadA.start();

        Thread.sleep(500);

        Thread threadB = new Thread(runnable);
        threadB.start();

        Thread.sleep(500);
        System.out.println(service.lock.hasQueuedThread(threadA));
        System.out.println(service.lock.hasQueuedThread(threadB));
        System.out.println(service.lock.hasQueuedThreads());
    }
}
false
true
true

   示例2:hasWaiters(newCondition)方法的作用是查询是否有线程正在等待与此锁定有关的condition条件。示例中10个线程都执行了await()方法,且都在等待newCondition条件。

package test2;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

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 notityMethod() {
        try {
            lock.lock();
            System.out.println("有没有线程正在等待newCondition?"
                    + lock.hasWaiters(newCondition) + " 线程数是多少?"
                    + lock.getWaitQueueLength(newCondition));
            newCondition.signal();
        } finally {
            lock.unlock();
        }
    }

}
package test2;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        final Service service = new Service();

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service.waitMethod();
            }
        };

        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.sleep(2000);
        service.notityMethod();
    }
}
有没有线程正在等待newCondition?true 线程数是多少?10

  12.方法isFair()、isHeldByCurrentThread()、isLocked()的测试

  示例1:isFair()的作用是判断是不是公平锁,在默认的情况下,ReentrantLock类使用的非公平锁。

package test1;

import java.util.concurrent.locks.ReentrantLock;

public class Service {

    private ReentrantLock lock;

    public Service(boolean isFair) {
        super();
        lock = new ReentrantLock(isFair);
    }

    public void serviceMethod() {
        try {
            lock.lock();
            System.out.println("公平锁情况:" + lock.isFair());
        } finally {
            lock.unlock();
        }
    }

}
package test1;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        final Service service1 = new Service(true);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service1.serviceMethod();
            }
        };
        Thread thread = new Thread(runnable);
        thread.start();

        final Service service2 = new Service(false);
        runnable = new Runnable() {
            @Override
            public void run() {
                service2.serviceMethod();
            }
        };
        thread = new Thread(runnable);
        thread.start();

    }
}
公平锁情况:true
公平锁情况:false

  示例2:isHeldByCurrentThread()方法的作用是查询当前线程是否保持此锁定,执行完lock.lock();后就保持锁定,返回true。

package test2;

import java.util.concurrent.locks.ReentrantLock;

public class Service {

    private ReentrantLock lock;

    public Service(boolean isFair) {
        super();
        lock = new ReentrantLock(isFair);
    }

    public void serviceMethod() {
        try {
            System.out.println(lock.isHeldByCurrentThread());
            lock.lock();
            System.out.println(lock.isHeldByCurrentThread());
        } finally {
            lock.unlock();
        }
    }

}
package test2;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        final Service service1 = new Service(true);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service1.serviceMethod();
            }
        };
        Thread thread = new Thread(runnable);
        thread.start();
    }
}
false
true

  示例3:isLocked()方法的作用是查询此锁定是否由任意线程保持,执行lock.lock();后改变返回值。

package test3;

import java.util.concurrent.locks.ReentrantLock;

public class Service {

    private ReentrantLock lock;

    public Service(boolean isFair) {
        super();
        lock = new ReentrantLock(isFair);
    }

    public void serviceMethod() {
        try {
            System.out.println(lock.isLocked());
            lock.lock();
            System.out.println(lock.isLocked());
        } finally {
            lock.unlock();
        }
    }

}
package test3;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        final Service service1 = new Service(true);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service1.serviceMethod();
            }
        };
        Thread thread = new Thread(runnable);
        thread.start();
    }
}
false
true

  13.方法lockInterruptibly()、tryLock()、tryLock(long timeout,TimeUnit unit)的测试

  示例1:调用lock.lock();时,即使线程B被interrupt中断了,也没有出现异常,线程A和线程B正常结束。

package service;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {

    public ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void waitMethod() {
        try {
            lock.lock();
            System.out
                    .println("lock begin " + Thread.currentThread().getName());
            for (int i = 0; i < Integer.MAX_VALUE / 10; i++) {
                Math.random();
            }
            System.out
                    .println("lock   end " + Thread.currentThread().getName());
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}
package test;

import service.MyService;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        final MyService service = new MyService();
        Runnable runnableRef = new Runnable() {
            @Override
            public void run() {
                service.waitMethod();
            }
        };

        Thread threadA = new Thread(runnableRef);
        threadA.setName("A");
        threadA.start();
        Thread.sleep(500);
        Thread threadB = new Thread(runnableRef);
        threadB.setName("B");
        threadB.start();
        threadB.interrupt();
        System.out.println("main end!");
    }
}
lock begin A
main end!
lock   end A
lock begin B
lock   end B

  示例2:修改成lock.lockInterruptibly();线程B被interrupt中断后,调用调用lockInterruptibly()方法会出现异常。说明了lockInterruptibly()方法的作用是如果当前线程未被中断,则获取锁定,如果已经被中断则出现异常。

package service;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {

    public ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void waitMethod() {
        try {
            lock.lockInterruptibly();
            System.out.println("lock " + Thread.currentThread().getName());
            for (int i = 0; i < Integer.MAX_VALUE / 10; i++) {
                Math.random();
            }
        } catch (InterruptedException e) {
            System.out.println("�߳�"+Thread.currentThread().getName()+"����catch~!");
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}
lock A
线程B进入catch~!
java.lang.InterruptedException
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(Unknown Source)
	at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(Unknown Source)
	at service.MyService.waitMethod(MyService.java:13)
	at test.Run$1.run(Run.java:12)
	at java.lang.Thread.run(Unknown Source)

  示例3:tryLock()方法的作用是,仅在调用时锁定未被另一个线程保持的情况下,才获取该锁定。

package service;

import java.util.concurrent.locks.ReentrantLock;

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() + "未获得锁");
        }
    }
}
package test;

import service.MyService;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        final MyService service = new MyService();

        Runnable runnableRef = new Runnable() {
            @Override
            public void run() {
                service.waitMethod();
            }
        };

        Thread threadA = new Thread(runnableRef);
        threadA.setName("A");
        threadA.start();
        Thread threadB = new Thread(runnableRef);
        threadB.setName("B");
        threadB.start();
    }
}
A已获得锁
B未获得锁
B已获得锁
A未获得锁

  示例4:tryLock(long timeout, TimeUnit.SECONDS)方法的作用是,如果锁定在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁定。

package service;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {

    public ReentrantLock lock = new ReentrantLock();

    public void waitMethod() {
        try {
            if (lock.tryLock(3, TimeUnit.SECONDS)) {
                System.out.println("      " + Thread.currentThread().getName()
                        + "获得锁的时间:" + System.currentTimeMillis());
                Thread.sleep(10000);
            } else {
                System.out.println("      " + Thread.currentThread().getName()
                        + "没有获得锁!");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}
package test;

import service.MyService;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        final MyService service = new MyService();

        Runnable runnableRef = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()
                        + "调用waitMethod" + System.currentTimeMillis());
                service.waitMethod();
            }
        };

        Thread threadA = new Thread(runnableRef);
        threadA.setName("A");
        threadA.start();
        Thread threadB = new Thread(runnableRef);
        threadB.setName("B");
        threadB.start();
    }
}
B调用waitMethod的时间:1525681079395
A调用waitMethod的时间:1525681079395
      B获得锁的时间:1525681079396
      A没有获得锁!

  14.方法awaitUninterruptibly()的使用

  示例1:使用condition.await();正常情况下,线程在启动3000毫秒后,被interrupt中断后会发生异常。

package service;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Service {

    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void testMethod() {
        try {
            lock.lock();
            System.out.println("wait begin");
            condition.await();
            System.out.println("wait   end");
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("catch");
        } finally {
            lock.unlock();
        }

    }
}
package extthread;

import service.Service;

public class MyThread extends Thread {

    private Service service;

    public MyThread(Service service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.testMethod();
    }

}
package test;

import service.Service;
import extthread.MyThread;

public class Run {

    public static void main(String[] args) {
        try {
            Service service = new Service();
            MyThread myThread = new MyThread(service);
            myThread.start();
            Thread.sleep(3000);
            myThread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
wait begin
java.lang.InterruptedException
catch
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.reportInterruptAfterWait(Unknown Source)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(Unknown Source)
	at service.Service.testMethod(Service.java:15)
	at extthread.MyThread.run(MyThread.java:16)

  示例2:修改成awaitUninterruptibly();然后删除catch部分,即使线程中断,程序也不会出现异常。

package service;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Service {

    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void testMethod() {
        try {
            lock.lock();
            System.out.println("wait begin");
            condition.awaitUninterruptibly();
            System.out.println("wait   end");
        } finally {
            lock.unlock();
        }

    }
}
wait begin

  15.方法awaitUntil()的使用

  示例:condition.awaitUntil(calendarRef.getTime());方法可以在指定等待时间后自动唤醒自己。

package service;

import java.util.Calendar;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Service {

    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void waitMethod() {
        try {
            Calendar calendarRef = Calendar.getInstance();
            calendarRef.add(Calendar.SECOND, 10);
            lock.lock();
            System.out.println("wait begin timer=" + System.currentTimeMillis());
            condition.awaitUntil(calendarRef.getTime());
            System.out.println("wait   end timer=" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    public void notifyMethod() {
        try {
            Calendar calendarRef = Calendar.getInstance();
            calendarRef.add(Calendar.SECOND, 10);
            lock.lock();
            System.out.println("notify begin timer=" + System.currentTimeMillis());
            condition.signalAll();
            System.out.println("notify   end timer=" + System.currentTimeMillis());
        } finally {
            lock.unlock();
        }

    }
}
package extthread;

import service.Service;

public class MyThreadA extends Thread {

    private Service service;

    public MyThreadA(Service service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.waitMethod();
    }

}
package extthread;

import service.Service;

public class MyThreadB extends Thread {

    private Service service;

    public MyThreadB(Service service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.notifyMethod();
    }

}

  Run1:在等待了10秒后自动唤醒自己。

package test;

import service.Service;
import extthread.MyThreadA;
import extthread.MyThreadB;

public class Run1 {

    public static void main(String[] args) throws InterruptedException {
        Service service = new Service();
        MyThreadA myThreadA = new MyThreadA(service);
        myThreadA.start();
    }

}
wait begin timer=1525681887037
wait   end timer=1525681897020

   Run2:在等待时间到达前,可以被其他线程提前唤醒。

package test;

import service.Service;
import extthread.MyThreadA;
import extthread.MyThreadB;

public class Run2 {

    public static void main(String[] args) throws InterruptedException {
        Service service = new Service();
        MyThreadA myThreadA = new MyThreadA(service);
        myThreadA.start();

        Thread.sleep(2000);

        MyThreadB myThreadB = new MyThreadB(service);
        myThreadB.start();
    }

}
wait begin timer=1525681991401
notify begin timer=1525681993380
notify   end timer=1525681993380
wait   end timer=1525681993380

  16.使用Condition实现顺序执行

  示例:使用Condition对象可以对线程执行的业务进行排序规划。使用3个Condition对象,同时通过设置nextPrintWho变量以及判断语句来实现按顺序打印。

package finaltools;

public class F {
    volatile public static int nextPrintWho = 1;
}
package test.run;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Run {

    volatile private static int nextPrintWho = 1;
    private static ReentrantLock lock = new ReentrantLock();
    final private static Condition conditionA = lock.newCondition();
    final private static Condition conditionB = lock.newCondition();
    final private static Condition conditionC = lock.newCondition();

    public static void main(String[] args) {

        Thread threadA = new Thread() {
            public void run() {
                try {
                    lock.lock();
                    while (nextPrintWho != 1) {
                        conditionA.await();
                    }
                    for (int i = 0; i < 3; i++) {
                        System.out.println("ThreadA " + (i + 1));
                    }
                    nextPrintWho = 2;
                    conditionB.signalAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };

        Thread threadB = new Thread() {
            public void run() {
                try {
                    lock.lock();
                    while (nextPrintWho != 2) {
                        conditionB.await();
                    }
                    for (int i = 0; i < 3; i++) {
                        System.out.println("ThreadB " + (i + 1));
                    }
                    nextPrintWho = 3;
                    conditionC.signalAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };

        Thread threadC = new Thread() {
            public void run() {
                try {
                    lock.lock();
                    while (nextPrintWho != 3) {
                        conditionC.await();
                    }
                    for (int i = 0; i < 3; i++) {
                        System.out.println("ThreadC " + (i + 1));
                    }
                    nextPrintWho = 1;
                    conditionA.signalAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };
        Thread[] aArray = new Thread[5];
        Thread[] bArray = new Thread[5];
        Thread[] cArray = new Thread[5];

        for (int i = 0; i < 5; i++) {
            aArray[i] = new Thread(threadA);
            bArray[i] = new Thread(threadB);
            cArray[i] = new Thread(threadC);

            aArray[i].start();
            bArray[i].start();
            cArray[i].start();
        }

    }
}
ThreadA 1
ThreadA 2
ThreadA 3
ThreadB 1
ThreadB 2
ThreadB 3
ThreadC 1
ThreadC 2
ThreadC 3
ThreadA 1
ThreadA 2
ThreadA 3
ThreadB 1
ThreadB 2
ThreadB 3
ThreadC 1
ThreadC 2
ThreadC 3
ThreadA 1
ThreadA 2
ThreadA 3
ThreadB 1
ThreadB 2
ThreadB 3
ThreadC 1
ThreadC 2
ThreadC 3
ThreadA 1
ThreadA 2
ThreadA 3
ThreadB 1
ThreadB 2
ThreadB 3
ThreadC 1
ThreadC 2
ThreadC 3
ThreadA 1
ThreadA 2
ThreadA 3
ThreadB 1
ThreadB 2
ThreadB 3
ThreadC 1
ThreadC 2
ThreadC 3

  二、使用ReentrantReadWriteLock类

  类ReentrantLock具有完全互斥排他的效果,即同一时间只有一个线程在执行ReentrantLock.lock()方法后面的任务。这样做虽然保证了实例变量的线程安全性,但效率确实非常低下的。所以可以使用ReentrantReadWriteLock类来加快运行效率,在某些不需要操作实例变量的方法中,完全可以使用读写锁ReentrantReadWriteLock来提升该方法的代码运行速度。

  读写锁表示也有两个锁,一个是读操作相关的锁,也成为共享锁;另一个是写操作相关的锁,也叫排他锁。也就是多个 读锁之间不互斥,读锁与写锁互斥,写锁与写锁互斥。在没有线程进入写操作时,进行读取操作的多个线程都可以获取该锁,而进行写入操作的线程只有在获取写锁后才能进行写入操作。即多个线程可以同时进行读取操作,但是同一时刻只允许一个线程进行写入操作。

  1.类ReentrantReadWriteLock的使用:读读共享

  示例:从输出结果可以看出,两个线程几乎同时进入lock()方法后面的代码。说明在此使用读锁lock.readLock().lock();可以提高程序运行效率,允许多个线程同时执行lock()后面的代码。

package service;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public 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 (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
package extthread;

import service.Service;

public class ThreadA extends Thread {

    private Service service;

    public ThreadA(Service service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.read();
    }
}
package extthread;

import service.Service;

public class ThreadB extends Thread {

    private Service service;

    public ThreadB(Service service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.read();
    }
}
package test;

import service.Service;
import extthread.ThreadA;
import extthread.ThreadB;

public class Run {

    public static void main(String[] args) {

        Service service = new Service();

        ThreadA a = new ThreadA(service);
        a.setName("A");

        ThreadB b = new ThreadB(service);
        b.setName("B");

        a.start();
        b.start();

    }

}
获得读锁B 1525682951639
获得读锁A 1525682951639

  2.类ReentrantReadWriteLock的使用:写写互斥

  示例:修改上例中的Service类,改成lock.writeLock().lock();从输出结果可以看出,同一时间只允许一个线程执行lock()后面的代码,两个线程执行lock()后面的代码的间隔是10000毫秒,即第一个线程执行完毕释放锁后第二个线程才可以执行。

package service;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public 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 (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
获得写锁A 1525683149041
获得写锁B 1525683159041

  3.类ReentrantReadWriteLock的使用:读写互斥

  示例:修改Service类,定义读方法和写方法,线程A读,线程B写,线程A执行1000毫秒后线程B执行,从输出结果可以看出,“读写”操作确实是互斥的。

package service;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public 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 (InterruptedException 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 (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
获得读锁A 1525683361081
获得写锁B 1525683371082

  4.类ReentrantReadWriteLock的使用:写读互斥

  示例:修改上例,使线程A写,线程B读,线程A执行1000毫秒后线程B执行,从输出结果可以看出,“写读”操作也是互斥的。

获得写锁A 1525683538622
获得读锁B 1525683548623
posted @ 2018-05-04 16:33  BigJunOba  阅读(708)  评论(0编辑  收藏  举报