Java并发编程:同步工具类
1.Semaphore类 一个计数信号量,通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。功能和锁有点类似,它一般用于控制对某组资源的访问权限。
acquire()用来获取一个许可,若无许可能够获得,则会一直等待,直到获得许可。
release()用来释放许可。注意,在释放许可之前,必须先获获得许可。
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 e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("线程 " + Thread.currentThread().getName()
+ " 进入,当前已有 " + (3 - sp.availablePermits())
+ "个线程并发");
try {
Thread.sleep((long) Math.random() * 1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("线程 " + Thread.currentThread().getName()
+ "即将离开");
sp.release();
System.out.println("线程 " + Thread.currentThread().getName()
+ " 已离开,当前已有" + (3 - sp.availablePermits())
+ "个线程并发");
}
};
service.execute(runnable);
}
}
}
2.CyclicBarrier类一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点。
一组线程等待至某个状态之后再全部同时执行,例如班级出外郊游,当所有人到齐后才出发到下一个目的地。
/*
集齐够了所有线程再进行下一步工作
*/
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();
}
}
3.CountDownLatch类一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
CountDownLatch 使用一个计数器来实现,它初始化为一个正,用来表示需要等待的活动事件数。countDown 方法使计数器减一,表示一个事件已经发生了,而await方法等待计数器达到零,此时表示所有需要等待的事件都已发生,只有当计数器到达零时,锁才会开起。如果计数器的初始值不为零,await会一直阻塞直到计数器为零,或者是等待线程中断或超时。
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); // 裁判吹一声口哨
// 将计数1初始化做一个开/关锁存器,调用countDown()的线程打开
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();
}
}
4.Exchanger类 两个线程可以交换对象的同步点。每个线程都在进入 exchange 方法时给出某个对象,相互接受对方准备的对象。
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 {
Thread.sleep((long) (Math.random() * 10000));
String data1 = "Drug";
System.out.println("线程" + Thread.currentThread().getName()
+ "正在把 " + data1 + " 换出去");
String data2 = (String) exchanger.exchange(data1);
System.out.println("线程" + Thread.currentThread().getName()
+ "换回的东西为 " + data2);
} catch (Exception e) {
e.printStackTrace();
}
}
});
service.execute(new Runnable() {
public void run() {
try {
Thread.sleep((long) (Math.random() * 10000));
String data1 = "Money";
System.out.println("线程" + Thread.currentThread().getName()
+ "正在把 " + data1 + " 换出去");
String data2 = (String) exchanger.exchange(data1);
System.out.println("线程" + Thread.currentThread().getName()
+ "换回的东西为" + data2);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}