Java并发程序设计(四)JDK并发包之同步控制
JDK并发包之同步控制
一、重入锁
重入锁使用java.util.concurrent.locks.ReentrantLock来实现。示例代码如下:
public class TryReentrantLock implements Runnable{ static ReentrantLock lock=new ReentrantLock();
static int i=0;
@Override
public void run() {
for(int j=0;j<10000;j++){
lock.lock();
try{
i++;
}finally {
lock.unlock();
} //重入锁可以反复进入,当然这种进入仅限于一个线程!因此可以如下:
/*lock.lock();
lock.lock();
try{
i++;
}finally {
lock.unlock();
lock.unlock();
}*/
}
} public static void main(String[] args) throws InterruptedException {
TryReentrantLock l=new TryReentrantLock();
Thread t1=new Thread(l);
Thread t2=new Thread(l);
t1.start(); t2.start();
t1.join(); t2.join();
System.out.println(i);
}
}
对于synchronized来说,如果一个线程在等待锁,那么结果只有两种情况,要么它获得这把锁继续执行,要么继续等待锁。而对于使用重入锁的线程来说则不同,线程在等待锁的过程中,程序可以根据需要取消对锁的请求。
public class IntLock implements Runnable{
public static ReentrantLock lock1=new ReentrantLock();
public static ReentrantLock lock2=new ReentrantLock();
int state; /*控制加锁顺序,便于产生死锁。*/
public IntLock(int state){
this.state=state;
}
@Override
public void run() {
try{
if(state==1){
lock1.lockInterruptibly(); //设置可中断的锁
try{
Thread.sleep(500); //便于产生死锁
}catch (InterruptedException e){
e.printStackTrace();
}
lock2.lockInterruptibly();
}else{
lock2.lockInterruptibly();
try{
Thread.sleep(500);
}catch (InterruptedException e){
e.printStackTrace();
}
lock1.lockInterruptibly();
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(lock1.isHeldByCurrentThread()) lock1.unlock();
if(lock2.isHeldByCurrentThread()) lock2.unlock();
System.out.println(Thread.currentThread().getName()+" :quit!");
}
} public static void main(String[] args) throws InterruptedException {
IntLock intLock1=new IntLock(1);
IntLock intLock2=new IntLock(2);
Thread t1=new Thread(intLock1);
t1.setName("t1");
Thread t2=new Thread(intLock2);
t2.setName("t2");
t1.start(); t2.start();
Thread.sleep(1000);
t2.interrupt();
}
}
使用tryLock()进行限时等待。
public class TimeLock implements Runnable{
public static ReentrantLock lock=new ReentrantLock();
@Override
public void run() {
try{
if(lock.tryLock(5, TimeUnit.SECONDS)){
//注意返回布尔值.如果使用无参数的tryLock方法,
// 当锁被占用时,线程会不等待,并返回false。
Thread.sleep(6000);
}else{
System.out.println("Get lock failed!");
}
}catch (Exception e){
e.printStackTrace();
}finally {
if (lock.isHeldByCurrentThread()) lock.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(); }
}
公平锁:
大多数情况下,锁的申请都是不公平,随机的。而公平锁,讲究“先来后到”!因此公平锁的一大特点是不会产生饥饿。重入锁允许我们对其公平性进行设置:
public ReentrantLock(boolean fair); //true表示公平锁
公平锁缺点:性能相对低下。
二、重入锁的好基友Condition
Condition的做用类似于wait()和notify()只不过Condition和ReentrantLock配合。
Condition接口的基本方法:
void await() throws InterruptedException //释放当前线程持有的锁,进入等待状态,当其他线程使用signal或signalAll()方法时继续执行。当线程被中断时会跳出等待。 void awaitUninterruptibly();与await()方法相似,当中断时不会跳出等待。 void signal();
void signalAll();
用法示例:
public class ReentrantCondition implements Runnable{
static ReentrantLock lock=new ReentrantLock();
static Condition condition=lock.newCondition(); @Override
public void run() {
try{
lock.lock();
System.out.println(Thread.currentThread().getName()+" is running fast!");
condition.await();
System.out.println(Thread.currentThread().getName()+" is going no.");
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
} public static void main(String[] args) throws InterruptedException {
ReentrantCondition rc=new ReentrantCondition();
Thread t=new Thread(rc,"King of Lock");
t.start(); Thread.sleep(2000);
lock.lock(); //调用signal前先要获得锁
condition.signal();
lock.unlock(); //调用singal后要释放锁,以让给被唤醒的线程。
}
}
三、允许多个线程同时访问:信号量(Semaphore)
Semaphore可以指定多个线程同时访问一个资源。
public Semaphore(int permits); //permits指定同时能有几个线程访问同一资源。
public Semaphore(int permits,boolean fair) //fair指定是否采用公平锁
Semaphore主要的逻辑方法有:
public void acquire() //尝试获得一个准入许可,若无法获得,则线程会等待,直到有线程释放了一个许可,或者当前线程被中断
public void acquireUninterruptibly() //不响应中断
public void release() //释放一个许可
四、ReadWriteLock读写锁
读写锁允许多个线程同时读。
五、CountDownLatch倒计时器
通常用来控制线程等待,可以让某个线程等待直到倒计时结束,再开始执行。
public CountDownLatch(int count) //count为需要完成几个线程上的任务,CountDownLatch上的线程才能继续执行。
示例代码:
public class CountDownLatchDemo implements Runnable{
static final CountDownLatch latch=new CountDownLatch(10); //需要完成10个线程的任务,
// CountDownLatch上的线程才能继续执行
static final CountDownLatchDemo demo=new CountDownLatchDemo(); @Override
public void run() {
try{
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+" :mission completed!");
latch.countDown();//通知CountDownLatch一个任务已经完成。
}catch (Exception e){
e.printStackTrace();
}
} public static void main(String[] args) throws InterruptedException {
ExecutorService ex= Executors.newFixedThreadPool(10);
for(int i=0;i<10;i++){
ex.submit(demo);
} latch.await(); //设置要等待其他线程完成的那个线程
System.out.println("Killed them all!");
ex.shutdown();
}
}
六、循环栅栏:CyclicBarrier
与CountDownLatch类似CyclicBarrier也是用来阻止线程继续执行,让线程进入等待状态。但此计数器可以反复使用。
public CyclicBarrier(int parties,Runnable barrierAction) //barrierAction为计数完成后要执行的动作
示例代码:
public class CyclicBarrierDemo { public static class Soldier implements Runnable{ private String name;
private final CyclicBarrier barrier; Soldier(String name,CyclicBarrier barrier){
this.name=name;
this.barrier=barrier;
} @Override
public void run() {
try{
barrier.await(); //进入等待状态,直到所有线程完成计数。
doWork(); //所有线程完成一次await,继续执行。
barrier.await(); //第二次await再次进入等待状态。
}catch (Exception e){ }
} void doWork(){
try{
Thread.sleep(Math.abs(new Random().nextInt()%10000));
}catch (Exception e){
e.printStackTrace();
}
System.out.println("任务完成!");
}
} public static class FlyRun implements Runnable{
boolean flag;
int count; public FlyRun(boolean flag,int count){
this.flag=flag;
this.count=count;
} @Override
public void run() {
if (flag) System.out.println("队长:"+count+" 个士兵完成任务!");
else {
System.out.println("队长:"+count+" 个士兵集合完毕!");
flag=true;
}
}
} public static void main(String[] args){
final int count=12;
Thread[] soldiers=new Thread[count];
boolean flag=false;
CyclicBarrier barrier=new CyclicBarrier(count,new FlyRun(flag,count));
//集合队伍
System.out.println("集合队伍!");
for(int j=0;j<count;j++){
System.out.println("士兵"+j+"报道!");
soldiers[j]=new Thread(new Soldier("士兵"+j,barrier));
soldiers[j].start();
}
}
}
七、线程阻塞工具类:LockSupport
LockSupport可以在线程内任意位置让线程阻塞。但与Object.wait()不同,它不需要先获得某个对象的锁,也不会抛出InterruptedException异常。示例代码:
public class LockSupportDemo { public static Object instance=new Object();
public static ChangThread t1=new ChangThread("t1");
public static ChangThread t2=new ChangThread("t2"); public static class ChangThread extends Thread{
public ChangThread(String name){
super.setName(name);
} @Override
public void run(){
synchronized(instance){
System.out.println("in"+getName());
LockSupport.park();
}
} } public static void main(String[] args) throws InterruptedException {
t1.start();
Thread.sleep(100);
t2.start();
LockSupport.unpark(t1); //即使unpark()发生在park前,程序也能正常执行。
LockSupport.unpark(t2);
t1.join();
t2.join();
}
}
park还支持中断影响,且不抛出异常。
Java并发程序设计(四)JDK并发包之同步控制的更多相关文章
- Java并发程序设计(一) 基础概念
Java并发程序设计(一) 基础概念 一.必须知道的几个概念 一)同步(Synchronous)和异步(Asynchronous) 同步:同步方法调用一旦开始,调用者必须等到方法调用返回后,才能继续后 ...
- [转]Java并发的四种风味:Thread、Executor、ForkJoin和Actor
这篇文章讨论了Java应用中并行处理的多种方法.从自己管理Java线程,到各种更好几的解决方法,Executor服务.ForkJoin 框架以及计算中的Actor模型. Java并发编程的4种风格:T ...
- 【Java并发编程四】关卡
一.什么是关卡? 关卡类似于闭锁,它们都能阻塞一组线程,直到某些事件发生. 关卡和闭锁关键的不同在于,所有线程必须同时到达关卡点,才能继续处理.闭锁等待的是事件,关卡等待的是其他线程. 二.Cycli ...
- Java 并发编程(四):如何保证对象的线程安全性
01.前言 先让我吐一句肺腑之言吧,不说出来会憋出内伤的.<Java 并发编程实战>这本书太特么枯燥了,尽管它被奉为并发编程当中的经典之作,但我还是忍不住.因为第四章"对象的组合 ...
- 【JAVA并发第四篇】线程安全
1.线程安全 多个线程对同一个共享变量进行读写操作时可能产生不可预见的结果,这就是线程安全问题. 线程安全的核心点就是共享变量,只有在共享变量的情况下才会有线程安全问题.这里说的共享变量,是指多个线程 ...
- Java并发(四):happens-before
happens-before 一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在happens-before关系 happen-before原则是JMM中非常重要的原则,它是判断数据是 ...
- Java并发程序设计(五)JDK并发包之线程复用:线程池
线程复用:线程池 一.为什么需要线程池 为了避免系统频繁地创建和销毁线程,使用线程池让线程进行复用.(即创建线程变成了从线程池中获取空闲线程,销毁线程变成了把线程放回线程池中.) 二.JDK对线程池的 ...
- Java高并发程序设计学习笔记(五):JDK并发包(各种同步控制工具的使用、并发容器及典型源码分析(Hashmap等))
转自:https://blog.csdn.net/dataiyangu/article/details/86491786#2__696 1. 各种同步控制工具的使用1.1. ReentrantLock ...
- Java并发(四)线程池使用
上一篇博文介绍了线程池的实现原理,现在介绍如何使用线程池. 目录 一.创建线程池 二.向线程池提交任务 三.关闭线程池 四.合理配置线程池 五.线程池的监控 线程池创建规范 一.创建线程池 我们可以通 ...
随机推荐
- 【转】wpf中的xmlns命名空间为什么是一个网址,代表了什么意思
wpf中的xmlns命名空间为什么是一个网址,代表了什么意思 http://blog.csdn.net/catshitone/article/details/71213371
- Bootstrap3.0学习第一轮(入门)
详情请查看 http://aehyok.com/Blog/Detail/7.html 个人网站地址:aehyok.com QQ 技术群号:206058845,验证码为:aehyok 本文文章链接:ht ...
- saltstack自动化运维系列⑦SaltStack实践配置管理安装zabbix
saltstack自动化运维系列⑥SaltStack实践配置管理安装zabbix 1.添加管理zabbix的sls文件# vim /srv/salt/base/init/zabbix_agent.sl ...
- centos6下通用二进制安装mysql5.5.33
mysql5.5通用二进制格式安装方法 1.解压到 /usr/local 目录 # tar xf mysql-5.5.33-linux2.6-x86_64.tar.gz -C /usr/local 2 ...
- 转载:2.2.3 配置项的注释《深入理解Nginx》(陶辉)
原文:https://book.2cto.com/201304/19628.html 如果有一个配置项暂时需要注释掉,那么可以加"#"注释掉这一行配置.例如: #pid ...
- [java]用md5来判断两个文件是否完全相同
1. 前言 由于相比较两张图片是否是相同,如果通过像素点比较感觉速度比较慢,当很多图片进行比较时,效率就低很多了.由于每个文件md5基本上是唯一的,所以用获取文件的md5来判断是否相同文件. 2. 代 ...
- PYTHON-模块 json pickle shelve xml
""" pickle 和 shevle 序列化后得到的数据 只有python才能解析 通常企业开发不可能做一个单机程序 都需要联网进行计算机间的交互 我们必须保证这个数据 ...
- NodeJs>------->>第二章:Node.js中交互式运行环境--------REL
第二章:Node.js中交互式运行环境--------REL 一:REPL运行环境概述 C:\Users\junliu>node > foo = 'bar' ; 'bar' > 二: ...
- Nginx 下Thinkphp5伪静态
server { listen 80; server_name all.bjed.com; root "F:\www\asdata"; location / { index ind ...
- python+selenium六:等待相关
显式等待(sleep): 固定的等待(死等),不管页面有没有加载完,都等设置的时间过了再做下一步操作 隐式等待 全局生效,只写一次即可(仅当前页面),缺点:如果页面一直转圈,如:js出错将等待到所设置 ...