除了锁,java还有一些别的方法可以控制同步:
1、JDK1.5 Exchange 两个线程互换数据
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Exchange 2个线程之间交换数据
*/
public class ExchangeTest {
/**
* @param args
*/
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final Exchanger<String> exchanger = new Exchanger<>();
service.execute(new Runnable() {
@Override
public void run() {
try {
String data2 = exchanger.exchange("zjw");
System.out.println("线程" + Thread.currentThread().getName() + "换回的数据为" + data2);
} catch (Exception e) {
// TODO: handle exception
}
}
});
service.execute(new Runnable() {
@Override
public void run() {
try {
String data2 = exchanger.exchange("lfw");
System.out.println("线程" + Thread.currentThread().getName() + "换回的数据为" + data2);
} catch (Exception e) {
// TODO: handle exception
}
}
});
}
}
2、Semaphore
20个人去银行存款,但是该银行只有两个办公柜台,有空位则上去存钱,没有空位则只能去排队等待
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
/**
* 线程信号量Semaphore的运用
*
* @author XIEHEJUN
*
*/
public class SemaphoreThread {
private int a = 0;
/**
* 银行存钱类
*/
class Bank {
private int account = 100;
public int getAccount() {
return account;
}
public void save(int money) {
account += money;
}
}
/**
* 线程执行类,每次存10块钱
*/
class NewThread implements Runnable {
private Bank bank;
private Semaphore semaphore;
public NewThread(Bank bank, Semaphore semaphore) {
this.bank = bank;
this.semaphore = semaphore;
}
@Override
public void run() {
int b = a++;
if (semaphore.availablePermits() > 0) {
System.out.println("线程" + b + "启动,进入银行,有位置立即去存钱");
} else {
System.out.println("线程" + b + "启动,进入银行,无位置,去排队等待等待");
}
try {
semaphore.acquire();
bank.save(10);
System.out.println(b + "账户余额为:" + bank.getAccount());
Thread.sleep(1000);
System.out.println("线程" + b + "存钱完毕,离开银行");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 建立线程,调用内部类,开始存钱
*/
public void useThread() {
Bank bank = new Bank();
// 定义10个新号量
Semaphore semaphore = new Semaphore(2);
// 建立一个缓存线程池
ExecutorService es = Executors.newCachedThreadPool();
// 建立20个线程
for (int i = 0; i < 10; i++) {
// 执行一个线程
es.submit(new Thread(new NewThread(bank, semaphore)));
}
// 关闭线程池
es.shutdown();
// 从信号量中获取两个许可,并且在获得许可之前,一直将线程阻塞
semaphore.acquireUninterruptibly(2);
System.out.println("到点了,工作人员要吃饭了");
// 释放两个许可,并将其返回给信号量
semaphore.release(2);
}
public static void main(String[] args) {
SemaphoreThread test = new SemaphoreThread();
test.useThread();
}
}
3、.CyclicBarrier
通过它可以实现让一组线程等待至某个状态之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用。我们暂且把这个状态就叫做barrier,当调用await()方法之后,线程就处于barrier了。
CyclicBarrier cb = new CyclicBarrier(int n);// 一组线程等待至某个状态之后再全部同时执行
CyclicBarrier cb = new CyclicBarrier(int n,Runnable thread);// 一组线程等待至某个状态之后先执行thread线程,再全部同时执行其他线程
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/*
* 处理同一个动作有多个线程同时执行的场景
*/
public class TestCyclicBarrier {
public static void main(String[] args) {
//1.得到一个CyclicBarrier实例
CyclicBarrier cb = new CyclicBarrier(4);
new Thread(new Fishing(cb),"1").start();
new Thread(new Fishing(cb),"2").start();
new Thread(new Fishing(cb),"3").start();
new Thread(new Fishing(cb),"4").start();
}
static class Fishing implements Runnable{
CyclicBarrier cb;
public Fishing(CyclicBarrier cb) {
this.cb = cb;
}
@Override
public void run() {
try {
cb.await();
System.out.println("第(" + Thread.currentThread().getName() + ")个人开始钓鱼");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}
4、CountDownLatch(倒计时计数器)
所有线程执行完后,再执行某个线程
百米赛跑,4名运动员选手到达场地等待裁判口令,裁判一声口令,选手听到后同时起跑,当所有选手到达终点,裁判进行汇总汇总排名。
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CountdownLatchTest2 {
public static void main(String[] args) {
ExecutorService service = Executors. newCachedThreadPool();
final CountDownLatch cdOrder = new CountDownLatch(1);
final CountDownLatch cdAnswer = new CountDownLatch(4);
for (int i = 0; i < 4; 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("所有选手都到达终点" );
System. out.println("裁判" + Thread.currentThread ().getName() + "汇总成绩排名" );
} catch (Exception e) {
e.printStackTrace();
}
service.shutdown();
}
}