j.u.c同步器使用总结

从jdk1.5开始,java.util.concurrent提供了在并发编程中很常用的实用工具类,包括几个小的、已标准化的可扩展框架,以及一些提供有用功能的类。没有这些类,并发功能会很难实现或实现起来冗长乏味。本文将关注j.u.c中提供的四种同步器: CountDownLatch, CyclicBarrier, Semaphore, Exchanger,它们用于辅助实现一些常见的同步场景。下面将分别介绍java并发包中的每种同步器使用方法和常见场景。

[size=large]一、CountDownLatch[/size]
[b]1. 功能[/b]
用于同步多个线程的完成操作,让先完成的线程进行等待,直至所有线程完成。

[b]2. 使用方法[/b]
1)新建CountDownLatch对象,定义总计数器latch。
2)调用await()方法,使当前线程进入等待状态。
3)调用countDown()方法,使计数器减一,当计数器降为0时,线程重新恢复运行。

[b]3. 示例[/b]
场景: 10个同事约好周末一起去西湖游玩,先在公司集合完毕,到齐后一起出发,每人骑一辆自行车,统一在西湖集合。
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class CountDownLatchTest {

public static void main(String[] args) {
final CountDownLatch start = new CountDownLatch(1);
final CountDownLatch done = new CountDownLatch(10);
ExecutorService executor = Executors.newFixedThreadPool(10);
for(int i = 0; i<10; i++){
executor.execute(new Employee(start, done));
}

start.countDown();
System.out.println("大部队已经准备出发.");
try {
done.await();
} catch (InterruptedException e) {

}
System.out.println("大部队在西湖集结完毕.");
executor.shutdown();

}
}

class Employee implements Runnable {
private CountDownLatch start;
private CountDownLatch done;

public Employee(CountDownLatch start, CountDownLatch done){
this.start = start;
this.done = done;
}

@Override
public void run() {
//到公司后等待
try {
start.await();
} catch (InterruptedException e) {

}

System.out.println(Thread.currentThread() + "从公司出发,去西湖路上.");
try {
Thread.sleep(new Random().nextInt(5000));
} catch (InterruptedException e1) {
}

//哥已经先到了
done.countDown();
}

}



[size=large]二、CyclicBarrier [/size]
[b]1. 功能[/b]
类似CountDownLatch,用于多次的同步多个线程的完成操作。

[b]2. 使用方法[/b]
1)新建CyclicBarrier对象,定义总计数器和结束后的下一步动作。
2)调用await()方法,使当前线程进入等待;当await()方法的调用次数达到总计数器时,各等待线程恢复运行。

[b]3. 示例[/b]
场景: 再考虑上面提到的场景,10个同事约好周末一起去西湖游玩,先在公司集合完毕;每人骑一辆自行车,在西湖集合完毕;大家再分散活动,中午在苏堤集合,一起吃午饭。如果采用CountDownLatch,需要定义三个CountDownLatch,下面演示如何使用CyclicBarrier解决这类问题。
import java.util.Random;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class CyclicBarrierTest {

public static void main(String[] args) {
final CyclicBarrier barrier = new CyclicBarrier(10, new Runnable(){
@Override
public void run() {
System.out.println("大部队集合完毕了。");
}

});

ExecutorService executor = Executors.newFixedThreadPool(10);
for(int i = 0; i<10; i++){
final int num = i;
executor.execute(new Runnable(){
@Override
public void run() {
System.out.println("num: " + num + " 从公司出发了.");
try {
Thread.sleep(new Random().nextInt(5000));
barrier.await(); // 在西湖等待大部队

System.out.println("num: " + num + " 在西湖开始游玩.");

Thread.sleep(new Random().nextInt(5000));
barrier.await(); //等待大部队就餐
} catch (Exception e1) {
}
}
});
}

executor.shutdown();
}
}



[size=large]三、Semaphore [/size]
[b]1. 功能[/b]
一个计数信号量,用于限制可以访问某些资源的线程数目。

[b]2. 使用方法[/b]
1)新建Semaphore对象,定义资源数目。
2)线程通过acquire()获取资源,通过release()释放资源。

[b]3. 示例[/b]
场景: 10个同事一起去游戏机厅打游戏,但游戏机厅只有四台游戏机,下面示例说明使用Semaphore限制同时玩游戏机的同事数目。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;


public class SemaphoreTest {

public static void main(String[] args) {
final Semaphore semaphore = new Semaphore(2,true);

ExecutorService executor = Executors.newFixedThreadPool(10);
for(int i = 0; i<10; i++){
final int num = i;
executor.execute(new Runnable(){
@Override
public void run() {
System.out.println("num: " + num + " 想要打游戏. 还有" + semaphore.availablePermits() + "台游戏机.");
try {
semaphore.acquire(1);
} catch (InterruptedException e) {

}
System.out.println("num: " + num + " 开始打游戏. 还有" + semaphore.availablePermits() + "台游戏机.");
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {
}

semaphore.release();
System.out.println("num: " + num + " 结束打游戏. 还有" + semaphore.availablePermits() + "台游戏机.");
}
});
}
executor.shutdown();
}
}


[size=large]四、Exchanger[/size]
[b]1. 功能[/b]
两个线程可以交换对象的同步点,每个线程给出对象,并接受其他线程返回时给出的对象。

[b]2. 使用方法[/b]
1)新建Exchanger对象。
2)每个线程交换对象时,调用exchanger.exchange(),完成对象交换。

[b]3. 示例[/b]
场景: 一黄牛最近拿到一部小米手机,想卖给一位同事,双方约好在公司门口交易,一手交钱,一手交货。
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExchangerTest {
public static void main(String[] args) {
final Exchanger exchanger = new Exchanger();

ExecutorService executor = Executors.newCachedThreadPool();
executor.execute(new Runnable(){
@Override
public void run() {
String money = "钞票";
System.out.println("同事有: " + money);
try {
String goods1 = (String) exchanger.exchange(money);
System.out.println("同事有: " + goods1);
} catch (InterruptedException e) {
}
}
});

executor.execute(new Runnable(){
@Override
public void run() {
String goods2 = "小米手机";
System.out.println("黄牛有: " + goods2);

//黄牛很忙,迟到一会
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {
}

try {
String money = (String) exchanger.exchange(goods2);
System.out.println("黄牛有: " + money);
} catch (InterruptedException e) {
}
}
});
executor.shutdown();
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值