java exchange同步_Java同步工具类总结

先谈谈闭锁和栅栏的区别:

1.关键区别在于,所有线程必须同时到达栅栏位置,才能继续执行。

2.闭锁用于等待某一个事件的发生,举例:CountDownLatch中await方法等待计数器为零时,所有事件才可继续执行。而栅栏是等待其他线程到位,所有事件才可继续下一步。例如:几个家庭决定在某个地方集合:“所有人6:00在麦当劳碰头,到了以后要等其他人,之后再讨论下一步要做的事情”。

Semaphore(闭锁)

这个东西和之前的synchronized干的事差不多。

synchronized保证了,我管理的那部分代码同一时刻只有一个线程能访问

Semaphore保证了,我管理的那部分代码同一时刻最多可以有n个线程访问

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Semaphore;

public class SemaphoreTest {

public static void main(String[] args) {

ExecutorService service = Executors.newCachedThreadPool();

final Semaphore sp = new Semaphore(3);

for(int i=0;i<10;i++){

Runnable runnable = new Runnable(){

public void run(){

try {

sp.acquire();

} catch (InterruptedException e1) {

e1.printStackTrace();

}

System.out.println("线程" + Thread.currentThread().getName() +

"进入,当前已有" + (3-sp.availablePermits()) + "个并发");

try {

Thread.sleep((long)(Math.random()*10000));

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("线程" + Thread.currentThread().getName() +

"即将离开");

sp.release();

//下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元

System.out.println("线程" + Thread.currentThread().getName() +

"已离开,当前已有" + (3-sp.availablePermits()) + "个并发");

}

};

service.execute(runnable);

}

}

}

运行结果如下:

线程pool-1-thread-2进入,当前已有2个并发

线程pool-1-thread-1进入,当前已有2个并发

线程pool-1-thread-3进入,当前已有3个并发

线程pool-1-thread-1即将离开

线程pool-1-thread-1已离开,当前已有2个并发

线程pool-1-thread-4进入,当前已有3个并发

线程pool-1-thread-3即将离开

线程pool-1-thread-3已离开,当前已有2个并发

线程pool-1-thread-5进入,当前已有3个并发

线程pool-1-thread-2即将离开

线程pool-1-thread-2已离开,当前已有2个并发

线程pool-1-thread-6进入,当前已有3个并发

线程pool-1-thread-4即将离开

线程pool-1-thread-4已离开,当前已有2个并发

线程pool-1-thread-7进入,当前已有3个并发

线程pool-1-thread-5即将离开

线程pool-1-thread-5已离开,当前已有2个并发

线程pool-1-thread-8进入,当前已有3个并发

线程pool-1-thread-8即将离开

线程pool-1-thread-9进入,当前已有3个并发

线程pool-1-thread-8已离开,当前已有3个并发

线程pool-1-thread-6即将离开

线程pool-1-thread-6已离开,当前已有2个并发

线程pool-1-thread-10进入,当前已有3个并发

线程pool-1-thread-10即将离开

线程pool-1-thread-10已离开,当前已有2个并发

线程pool-1-thread-7即将离开

线程pool-1-thread-7已离开,当前已有1个并发

线程pool-1-thread-9即将离开

线程pool-1-thread-9已离开,当前已有0个并发

CountDownLatch (闭锁)

它保证了什么功能呢?其实和CycliBarrier也类似。

看下面这个图

3cddaeb88a68d138c7a67691fa531c5e.png

这就是CycleBarrier,线程自己管理自己,大家看到人都到齐了,才继续走。

这个是CountDownLatch,由他人来协调进度。

c6c103b8c940f1969995be6f2e592dd3.png

例如跑步的时候,有个裁判,等所有的人都到齐了,他吹哨,然后大家开始跑,等所有人都跑完了,他才公布成绩。

import java.util.concurrent.CountDownLatch;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class CountdownLatchTest {

public static void main(String[] args) {

ExecutorService service = Executors.newCachedThreadPool();

final CountDownLatch cdOrder = new CountDownLatch(1);

final CountDownLatch cdAnswer = new CountDownLatch(3);

for(int i=0;i<3;i++){

Runnable runnable = new Runnable(){

public void run(){

try {

System.out.println("线程" + Thread.currentThread().getName() +

"正准备接受命令");

cdOrder.await();

System.out.println("线程" + Thread.currentThread().getName() +

"已接受命令");

Thread.sleep((long)(Math.random()*10000));

System.out.println("线程" + Thread.currentThread().getName() +

"回应命令处理结果");

cdAnswer.countDown();

} catch (Exception e) {

e.printStackTrace();

}

}

};

service.execute(runnable);

}

try {

Thread.sleep((long)(Math.random()*10000));

System.out.println("线程" + Thread.currentThread().getName() +

"即将发布命令");

cdOrder.countDown();

System.out.println("线程" + Thread.currentThread().getName() +

"已发送命令,正在等待结果");

cdAnswer.await();

System.out.println("线程" + Thread.currentThread().getName() +

"已收到所有响应结果");

} catch (Exception e) {

e.printStackTrace();

}

service.shutdown();

}

}

运行结果如下

线程pool-1-thread-3正准备接受命令

线程pool-1-thread-1正准备接受命令

线程pool-1-thread-2正准备接受命令

线程main即将发布命令

线程main已发送命令,正在等待结果

线程pool-1-thread-3已接受命令

线程pool-1-thread-2已接受命令

线程pool-1-thread-1已接受命令

线程pool-1-thread-3回应命令处理结果

线程pool-1-thread-1回应命令处理结果

线程pool-1-thread-2回应命令处理结果

线程main已收到所有响应结果

CountDownLatch里面有个计数器,初始值就是new countdownlatch时传入的

wait方法会一直等待,直到计数器的值变为0

coutdown方法可以让计数器的值减一

CycleBarrier(栅栏)

CycleBarrier 能做到让n个线程互相等待,当n个线程都做到某一步后,再继续下一步。

例如下面的例子,5个人去旅游,设置abc三个中途节点,所有人都到达a之后在继续走向b,所有人都到达b,然后才继续走向c。

import java.util.concurrent.CyclicBarrier;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class CyclicBarrierTest {

public static void main(String[] args) {

ExecutorService service = Executors.newCachedThreadPool();

final CyclicBarrier cb = new CyclicBarrier(3);

for(int i=0;i<3;i++){

Runnable runnable = new Runnable(){

public void run(){

try {

Thread.sleep((long)(Math.random()*10000));

System.out.println("线程" + Thread.currentThread().getName() +

"即将到达集合地点1,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));

cb.await();

Thread.sleep((long)(Math.random()*10000));

System.out.println("线程" + Thread.currentThread().getName() +

"即将到达集合地点2,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));

cb.await();

Thread.sleep((long)(Math.random()*10000));

System.out.println("线程" + Thread.currentThread().getName() +

"即将到达集合地点3,当前已有" + (cb.getNumberWaiting() + 1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));

cb.await();

} catch (Exception e) {

e.printStackTrace();

}

}

};

service.execute(runnable);

}

service.shutdown();

}

}

运行结果如下:

线程pool-1-thread-2即将到达集合地点1,当前已有1个已经到达,正在等候

线程pool-1-thread-1即将到达集合地点1,当前已有2个已经到达,正在等候

线程pool-1-thread-3即将到达集合地点1,当前已有3个已经到达,都到齐了,继续走啊

线程pool-1-thread-1即将到达集合地点2,当前已有1个已经到达,正在等候

线程pool-1-thread-3即将到达集合地点2,当前已有2个已经到达,正在等候

线程pool-1-thread-2即将到达集合地点2,当前已有3个已经到达,都到齐了,继续走啊

线程pool-1-thread-1即将到达集合地点3,当前已有1个已经到达,正在等候

线程pool-1-thread-2即将到达集合地点3,当前已有2个已经到达,正在等候

线程pool-1-thread-3即将到达集合地点3,当前已有3个已经到达,都到齐了,继续走啊

Exchange(栅栏)

A线程有数据1,它需要与B线程的数据2做交换

B线程有数据2,它需要与A线程的数据1做交换

那么什么时候交换呢?得等AB都做好准备才行。

import java.util.concurrent.Exchanger;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class ExchangerTest {

public static void main(String[] args) {

ExecutorService service = Executors.newCachedThreadPool();

final Exchanger exchanger = new Exchanger();

service.execute(new Runnable(){

public void run() {

try {

String data1 = "zxx";

System.out.println("线程" + Thread.currentThread().getName() +

"正在把数据" + data1 +"换出去");

Thread.sleep((long)(Math.random()*10000));

String data2 = (String)exchanger.exchange(data1);

System.out.println("线程" + Thread.currentThread().getName() +

"换回的数据为" + data2);

}catch(Exception e){

}

}

});

service.execute(new Runnable(){

public void run() {

try {

String data1 = "lhm";

System.out.println("线程" + Thread.currentThread().getName() +

"正在把数据" + data1 +"换出去");

Thread.sleep((long)(Math.random()*10000));

String data2 = (String)exchanger.exchange(data1);

System.out.println("线程" + Thread.currentThread().getName() +

"换回的数据为" + data2);

}catch(Exception e){

}

}

});

}

}

运行结果如下:

线程pool-1-thread-1正在把数据zxx换出去

线程pool-1-thread-2正在把数据lhm换出去

线程pool-1-thread-2换回的数据为zxx

线程pool-1-thread-1换回的数据为lhm

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值