一、Semaphore
1、作用
控制访问某一特定资源的线程数量,例如数据库连接、mq连接等等
2、举例说明
1)下面举个例子,让两个线程交替打印ABABABABABAB,不能同时打印AA或者BB
package cn.enjoy.controller.thread.DBPollSemaphore;
import java.util.concurrent.Semaphore;
/**
* @author:wangle
* @description:
* @version:V1.0
* @date:2020-03-22 21:22
**/
public class BDPollSemaphore {
private final static Semaphore outA = new Semaphore(1);
private final static Semaphore outB = new Semaphore(0);
public BDPollSemaphore(){
}
private static class OutA extends Thread{
@Override
public void run(){
while(true){
try {
outA.acquire();
System.out.println("A");
Thread.sleep(1000);
outB.release();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
private static class OutB extends Thread{
@Override
public void run(){
while(true){
try {
outB.acquire();
System.out.println("B");
Thread.sleep(1000);
outA.release();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
public static void main(String[] args){
new OutA().start();
new OutB().start();
}
}
结果如图,可见两个线程顺序执行,因为我们使用了信号量进行了控制。
2)数据库连接池实现
package cn.enjoy.controller.thread.DBPollSemaphore;
import cn.enjoy.controller.thread.DBPOLL.SqlConnectImpl;
import java.sql.Connection;
import java.util.LinkedList;
import java.util.concurrent.Semaphore;
/**
* @author wangle25
* @description
* @date 21:59 2020-03-22
* @param
* @return
**/
public class DBPoolSemaphore {
private final static int POOL_SIZE = 10;
private final Semaphore useful,useless;//useful表示可用的数据库连接,useless表示已用的数据库连接
public DBPoolSemaphore() {
this. useful = new Semaphore(POOL_SIZE);
this.useless = new Semaphore(0);
}
//存放数据库连接的容器
private static LinkedList<Connection> pool = new LinkedList<Connection>();
//初始化池
static {
for (int i = 0; i < POOL_SIZE; i++) {
pool.addLast(SqlConnectImpl.fetchConnection());
}
}
/*归还连接*/
public void returnConnect(Connection connection) throws InterruptedException {
if(connection!=null) {
System.out.println("当前有"+useful.getQueueLength()+"个线程等待数据库连接!!"
+"可用连接数:"+useful.availablePermits());
useless.acquire();
synchronized (pool) {
pool.addLast(connection);
}
useful.release();
}
}
/*从池子拿连接*/
public Connection takeConnect() throws InterruptedException {
useful.acquire();
Connection conn;
synchronized (pool) {
conn = pool.removeFirst();
}
useless.release();
return conn;
}
}
package cn.enjoy.controller.thread.DBPollSemaphore;
import java.sql.Connection;
import java.util.Random;
/**
* @author wangle25
* @description
* @date 21:59 2020-03-22
* @param
* @return
**/
public class AppTest {
private static DBPoolSemaphore dbPool = new DBPoolSemaphore();
//业务线程
private static class BusiThread extends Thread{
@Override
public void run() {
Random r = new Random();//让每个线程持有连接的时间不一样
long start = System.currentTimeMillis();
try {
Connection connect = dbPool.takeConnect();
System.out.println("Thread_"+Thread.currentThread().getId()
+"_获取数据库连接共耗时【"+(System.currentTimeMillis()-start)+"】ms.");
Thread.sleep(100+r.nextInt(100));//模拟业务操作,线程持有连接查询数据
System.out.println("查询数据完成,归还连接!");
dbPool.returnConnect(connect);
} catch (InterruptedException e) {
}
}
}
public static void main(String[] args) {
for (int i = 0; i < 50; i++) {
Thread thread = new BusiThread();
thread.start();
}
}
}
如图,前10个线程未阻塞,直接获取到sql连接,接下来等待获取到连接的线程使用完成归还连接后,其他线程才能继续获取连接
二、Exchanger
1、作用
两个线程之间进行数据的交换
package cn.enjoy.controller.thread.Exchanger;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Exchanger;
/**
* @author:wangle
* @description:使用Exchanger
* @version:V1.0
* @date:2020-03-23 20:24
**/
public class UseExchanger {
private static final Exchanger<List<Integer>> exchanger = new Exchanger<>();
private static class ThreadA extends Thread{
@Override
public void run(){
List<Integer> list = new ArrayList();
try {
list.add(1);
list.add(2);
list = exchanger.exchange(list);
}catch (Exception e){
}finally {
System.out.println("ThreadA data is:");
System.out.println(list);
}
}
}
private static class ThreadB extends Thread{
@Override
public void run(){
List<Integer> list = new ArrayList();
try {
list.add(3);
list.add(4);
list = exchanger.exchange(list);
}catch (Exception e){
}finally {
System.out.println("ThreadB data is:");
System.out.println(list);
}
}
}
public static void main(String[] args){
new ThreadA().start();
new ThreadB().start();
}
}