一、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();
}
}