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
Java多线程编程(四)Lock的使用的更多相关文章
- Java多线程核心技术(四)Lock的使用
本文主要介绍使用Java5中Lock对象也能实现同步的效果,而且在使用上更加方便. 本文着重掌握如下2个知识点: ReentrantLock 类的使用. ReentrantReadWriteLock ...
- java多线程系列(四)---Lock的使用
Lock的使用 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我的理 ...
- Java多线程编程核心技术--Lock的使用(一)
使用ReentrantLock类 在Java多线程中,可以使用synchronized关键字来实现线程之间的同步互斥,但在JDK1.5中新增加了ReentrantLock类也能达到同样的效果,并且在扩 ...
- Java多线程编程核心技术---Lock的基本概念和使用
Lock接口: ReentrantLock的基本功能: ReentrantLock的lock和unlock方法进行加锁,解锁.可以起到和synchronized关键字一样的效果: 选择性通知!!!: ...
- Java多线程编程核心技术(三)多线程通信
线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体.线程间的通信就是成为整体的必用方案之一,可以说,使线程间进行通信后,系统之间的交互性会更强大,在大大提高CPU利用率的同时 ...
- Java多线程编程核心技术(二)对象及变量的并发访问
本文主要介绍Java多线程中的同步,也就是如何在Java语言中写出线程安全的程序,如何在Java语言中解决非线程安全的相关问题.阅读本文应该着重掌握如下技术点: synchronized对象监视器为O ...
- Java多线程编程核心技术(一)Java多线程技能
1.进程和线程 一个程序就是一个进程,而一个程序中的多个任务则被称为线程. 进程是表示资源分配的基本单位,线程是进程中执行运算的最小单位,亦是调度运行的基本单位. 举个例子: 打开你的计算机上的任务管 ...
- Java多线程编程实战指南(核心篇)读书笔记(四)
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76690961冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...
- 【多线程】Java并发编程:Lock(转载)
原文链接:http://www.cnblogs.com/dolphin0520/p/3923167.html Java并发编程:Lock 在上一篇文章中我们讲到了如何使用关键字synchronized ...
- Java多线程编程实战指南(核心篇)读书笔记(三)
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76686044冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...
随机推荐
- Fliptile POJ-3279 DFS
题目链接:Fliptile 题目大意 有一个01矩阵,每一次翻转(0->1或者1->0)一个元素,就会把与他相邻的四个元素也一起翻转.求翻转哪些元素能用最少的步骤,把矩阵变成0矩阵. 思路 ...
- redis-分布式锁-消除竞争条件
因为信号量的设计过程中,获取一个信号量需要执行多个命令组成的流水,这样容易形成竞争条件. 为了消除信号量实现中所有可能出现的竞争条件,构建一个正确的计数信号量,需要在 信号量时,添加带有短暂超时时间的 ...
- Spring Boot (九): 微服务应用监控 Spring Boot Actuator 详解
1. 引言 在当前的微服务架构方式下,我们会有很多的服务部署在不同的机器上,相互是通过服务调用的方式进行交互,一个完整的业务流程中间会经过很多个微服务的处理和传递,那么,如何能知道每个服务的健康状况就 ...
- java多态的实现原理(JVM调用过程)(综合多篇文章,参考见文末)
一个对象变量可以指示多种实际类型的现象称为多态 允许不同类的对象对同一消息做出响应.方法的重载.类的覆盖正体现了多态. 1.多态的机制 1.1 本质上多态分两种 1.编译时多态(又称静态多态) 2.运 ...
- ELK 学习笔记之 Kibana安装
Kibana安装: 安装地址: https://www.elastic.co/downloads/kibana 安装: tar -zxvf kibana-5.6.1-linux-x86_64.tar. ...
- 【Java】获取当前操作系统桌面路径
//当前用户桌面 File desktopDir = FileSystemView.getFileSystemView() .getHomeDirectory(); String desktopPat ...
- 安装Office Visio 提示Office 16 Click-to-Run Extensibility Component
今天在安装 Office Visio 2016 时,点击安装程序,出现以下错误: 出现这个问题的原因就是你的电脑以前安装过32位的office,卸载时,注册表没有清理干净. 解决方案: 在win1 ...
- R-forestplot包| HR结果绘制森林图
本文首发于“生信补给站”微信公众号,https://mp.weixin.qq.com/s/2W1W-8JKTM4S4nml3VF51w 更多关于R语言,ggplot2绘图,生信分析的内容,敬请关注小号 ...
- tomcat容器是如何创建servlet类实例
当容器启动时,会读取在webapps目录下所有的web应用中的web.xml文件,然后对xml文件进行解析,并读取servlet注册信息. 然后,将每个应用中注册的servlet类都进行加载,并通过反 ...
- idea中的java web项目(添加jar包介绍)和java maven web项目目录结构
java web项目 web项目下web根目录名称是可以更改的 idea中新建java web项目,默认src为Sources Root,当然也可以手动改,在Sources Root下右键只能新建Pa ...