引言
读书读了一个多月了,这个月工作很多,空闲时间少,但是我还是在每天上班之前,下班之后挤出零星的时间写写博客,看看社区。每天下班以后,经常搜一些最近学习的相关知识点来加深理解。上次我介绍了前两章的内容,阅读人很少,并不多,但是这并不能打击我的积极性啦~ 今天我们继续讲解第三章的内容。
为了更好的支持并发程序,JDK内部提供了大量实用的API和框架,本章中主要介绍下面三个部分:
(1)首先,介绍关于同步控制的工具,之前介绍的synchronized关键字就是一种同步控制的手段,在本章中,将会看到更加丰富多彩的多线程控制方法。
(2)其次,介绍JDK对于线程池的支持,使用线程池,将很大程度上提高线程调度的性能。
(3)最后,向大家介绍JDK的一些并发容器,这些容器专为并行访问设计,是高效,安全,稳定的工具。
本章我将分为三部分,依次给大家进行讲解。
重入锁
- 使用方法
重入锁完全可以替代sysnchronized关键字。
重入锁使用java.util.concurrent.locks.ReentrantLock类来实现。
package JDK并发包;
import java.util.concurrent.locks.ReentrantLock;
/**
* author:select you from me
* func :重入锁的使用方法
*/
public class ReentranLockTest implements Runnable{
public static ReentrantLock lock = new ReentrantLock();
public static int i = 0;
@Override
public void run() {
for(int j=0;j<10000;j++){
//i++;
lock.lock();//必须显示的调用,比synchronized更灵活
try {
i++;
}finally {
lock.unlock();//最后必须释放锁
}
}
}
public static void main(String[] args) throws InterruptedException{
ReentranLockTest tlt = new ReentranLockTest();
Thread t1 = new Thread(tlt);
Thread t2 = new Thread(tlt);
t1.start();
t2.start();
Thread.sleep(1000);
System.out.println(i);
}
}
这里请注意下:
对同一段代码加两把锁也是可以的! 即:
lock.lock();//必须显示的调用,比synchronized更灵活
lock.lock();
try {
i++;
}finally {
lock.unlock();//最后必须释放锁
lock.unlock();//最后必须释放第二把锁
}
- 中断响应
对于synchronized来说,要么这个线程获取资源继续执行,要么一直等待,而重入锁提供了锁中断的骚操作。请看下边的代码:
package JDK并发包;
import java.util.concurrent.locks.ReentrantLock;
/**
* author:select you from me
* func :重入锁的锁中断
*/
public class ReentranLockIntteruptedTest implements Runnable{
public static ReentrantLock reentrantLock1 = new ReentrantLock();
public static ReentrantLock reentrantLock2 = new ReentrantLock();
int lock;
/*
* 控制加锁顺序,方便构造死锁
*/
public ReentranLockIntteruptedTest(int lock){
this.lock=lock;
}
@Override
public void run() {
try{
if(lock==1){
reentrantLock1.lockInterruptibly();//这个锁申请动作可以对中断进行响应,我们可以称之为中断锁
try{
Thread.sleep(500);
}catch(InterruptedException e){
}
reentrantLock2.lockInterruptibly();
} else{
reentrantLock2.lockInterruptibly();
try{
Thread.sleep(500);
}catch(InterruptedException e){
}
reentrantLock1.lockInterruptibly();
}
}catch (InterruptedException e){
e.printStackTrace();
}finally {
if(reentrantLock1.isHeldByCurrentThread()){
reentrantLock1.unlock();
}
if(reentrantLock2.isHeldByCurrentThread()){
reentrantLock2.unlock();
}
System.out.println(Thread.currentThread().getId()+":线程退出");
}
}
public static void main(String[] args) throws InterruptedException{
ReentranLockIntteruptedTest r1 = new ReentranLockIntteruptedTest(1);
ReentranLockIntteruptedTest r2 = new ReentranLockIntteruptedTest(2);
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
Thread.sleep(1000);
t2.interrupt();//由于t2中断了,线程响应中断,停止执行,线程退出,而t1则正常完成
}
}
程序执行结果如下:
10:线程退出
9:线程退出
java.lang.InterruptedException
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
at JDK并发包.ReentranLockIntteruptedTest.run(ReentranLockIntteruptedTest.java:37)
at java.lang.Thread.run(Thread.java:745)
- 锁申请等待限时
避免死锁除了可以采用等待外部通知的手段,还可以采用限时等待的手段。我们来看一下限时等待锁的使用:
package JDK并发包;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* author:select you from me
* func :限时等待锁
*/
public class TimeLock implements Runnable{
public static ReentrantLock reentrantLock = new ReentrantLock();
@Override
public void run() {
try{
if(reentrantLock.tryLock(5, TimeUnit.SECONDS)){//此方法也可以不带参数是用,如果锁被占用,立即返回false
Thread.sleep(6000);
}else{
System.out.println("get lock failed");
}
}catch (InterruptedException e){
e.printStackTrace();
}finally {
if(reentrantLock.isHeldByCurrentThread()){
reentrantLock.unlock();
}
}
}
public static void main(String []args){
TimeLock timeLock = new TimeLock();
Thread t1 = new Thread(timeLock);
Thread t2 = new Thread(timeLock);
t1.start();
t2.start();
}
}
- 公平锁
大多数情况下,系统在锁的等待队列中随机挑选线程,因此不能保证公平性。公平的锁一大特点就是按照时间的先后顺序,保证先到先得,从而不会产生饥饿现象。重入锁为我们提供了公平锁的实现。我们来看下代码:
package JDK并发包;
import java.util.concurrent.locks.ReentrantLock;
/**
* author:select you from me
* func :公平锁
*/
public class FairLock implements Runnable{
public static ReentrantLock reentrantLock = new ReentrantLock(true);//公平锁的定义
@Override
public void run() {
while (true){
try{
reentrantLock.lock();
System.out.println(Thread.currentThread().getName()+"获得锁");
}finally {
reentrantLock.unlock();
}
}
}
public static void main(String[]args) {
FairLock f1 = new FairLock();
Thread t1 = new Thread(f1);
Thread t2 = new Thread(f1);
t1.start();t2.start();
}
}
结果会一直按照这种顺序执行下去
Thread-0获得锁
Thread-1获得锁
Thread-0获得锁
Thread-1获得锁
Thread-0获得锁
Thread-1获得锁
Thread-0获得锁
下一节将要介绍condition,信号量,读写锁等,欢迎继续关注!
作者:select you from me
链接:https://mp.csdn.net/mdeditor/96439280
来源:CSDN
转载请联系作者获得授权并注明出处。