您的位置:首页 > 编程语言 > Java开发

java常用同步工具类

2016-04-18 13:55 471 查看


阻塞队列:

BlockingQueue接口定义了可阻塞的put和take方法,同时也提供了非阻塞式的offer和poll方法。如果队列已满,那么put方法将阻塞直到有空间可用,如果队列为空那么take方法将会阻塞直到队列中有元素可以使用。而offer以及poll两个方法当队列已满或者队列为空而存储失败的时候,返回false。因此阻塞队列是利用队列的存储状态来控制线程的执行状态。

可以利用阻塞队列使用生产者——消费者模式,生产者把数据放入队列,而消费者从队列中读取数据,生产者不需要知道消费者的状态和数量,消费者同样不需要知道生产者是谁,只是从队列中读取数据进行使用。

package com.pingan.home.demo;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;

public class BlockQueueShow {

static BlockingQueue<Integer> blockingQueue = new LinkedBlockingDeque<Integer>();;

public static void main(String[] args) {
Thread product = new Thread(new BlockQueueCreate());
Thread consumer = new Thread(new BlockQueueConsumer());
product.start();
consumer.start();
}

}

class BlockQueueCreate implements Runnable {

@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
BlockQueueShow.blockingQueue.put(i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}

}

class BlockQueueConsumer implements Runnable {

@Override
public void run() {
try {
while (true) {
System.out.println("Take:"+BlockQueueShow.blockingQueue.take());
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}

}



闭锁

闭锁可以延迟线程的进度直到其到达终止状态,闭锁相当于一扇门,初始状态为关闭的,没有任何线程可以通过,当满足一定的条件之后,闭锁这扇门会打开,允许所有的线程通过。闭锁可以确保某些任务知道其他的任务都完成之后才继续执行。

CountDownLatch是闭锁的一种实现,其状态包括一个计数器,该计数器在创建闭锁的时候被初始化为一个正整数,表示需要等待的事件数量。countDown方法用来改变闭锁的状态,调用一个闭锁的计数器就会递减,await方法会一直阻塞直到计数器变为0才开始执行。

package com.pingan.home.demo;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CountDownLatchShow {

/* 模拟了100米赛跑,10名选手已经准备就绪,只等裁判一声令下。当所有人都到达终点时,比赛结束。 */
public static void main(String[] args) throws InterruptedException {

ExecutorService runners = Executors.newFixedThreadPool(10);
/* 十名选手 */
for (int i = 0; i < 10; i++) {
Runner runner=new Runner();
runners.submit(runner);
}
/* begin减一,开始游戏 */
CountDownLatchUtil.begin.countDown();
long beginTime = System.nanoTime();
/* 等待end变为0,即所有选手到达终点 */
CountDownLatchUtil.end.await();
long lastEndTime = System.nanoTime();
System.out.println(lastEndTime - beginTime);
runners.shutdown();
}

}
class CountDownLatchUtil{
/* 开始的倒数锁 */
final static CountDownLatch begin = new CountDownLatch(1);
/* 结束的倒数锁 */
final static CountDownLatch end = new CountDownLatch(10);
}
class Runner implements Runnable {

@Override
public void run() {

try {
System.out.println(Thread.currentThread().getName()+ ":准备好");
long everyoneStartTime = System.nanoTime();
/**
* 1.如果当前计数为零,则此方法立即返回,顺序执行下面代码。
* 2.等待(begin.countDown()代码后才会释放所有等待线程)
*/
CountDownLatchUtil.begin.await();
Thread.sleep((long) (Math.random() * 1000));
long everyoneEndTime = System.nanoTime();
System.out.println(Thread.currentThread().getName()+ ":跑完"+ (everyoneEndTime - everyoneStartTime));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
/* 每个选手到达终点时,end就减一 */
CountDownLatchUtil.end.countDown();
}
}

}



信号量

计数信号量(Counting Semaphore)用来控制同时访问某个特定资源的操作数量,或者同时执行某个指定操作的数量,计数信号量还可以用来实现某种资源池或者对容器施加边界。

Semaphore中管理者一组虚拟的许可,通过构造函数来进行初始化。在执行操作的时候可以首先获得许可(r如果还有剩余的许可),并在使用后释放许可,如果没有许可那么acquire方法将阻塞直到有许可。release方法将返回一个许可信号量。因此我们可用使用Semaphore将任何容器变成有界的阻塞容器。

package com.pingan.home.demo;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class SemaphoreShow {

public static void main(String[] args) {
// 线程池
ExecutorService exec = Executors.newCachedThreadPool();
// 只能5个线程同时访问
final Semaphore semp = new Semaphore(5);
// 模拟20个客户端访问
for (int index = 0; index < 20; index++) {
final int NO = index;
Runnable run = new Runnable() {
public void run() {
try {
// 获取许可
semp.acquire();
System.out.println("Accessing: " + NO);
Thread.sleep((long) (Math.random() * 10000));
// 访问完后,释放 ,如果屏蔽下面的语句,则在控制台只能打印5条记录,之后线程一直阻塞
semp.release();
} catch (InterruptedException e) {
}
}
};
exec.execute(run);
}
// 退出线程池
exec.shutdown();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: