Java高并发程序设计(三)——JDK并发包(一)

引言

读书读了一个多月了,这个月工作很多,空闲时间少,但是我还是在每天上班之前,下班之后挤出零星的时间写写博客,看看社区。每天下班以后,经常搜一些最近学习的相关知识点来加深理解。上次我介绍了前两章的内容,阅读人很少,并不多,但是这并不能打击我的积极性啦~ 今天我们继续讲解第三章的内容。
为了更好的支持并发程序,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
转载请联系作者获得授权并注明出处。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值