semaphore
semaphore 有个参数counter 控制资源数量。counter 》0表示有资源可以访问,=0表示没有资源线程阻塞。semaphore.acquire()表示counter -1,semaphore.release()表示counter +1
public class PrintQueue {
private final Semaphore semaphore;
public PrintQueue(){
semaphore=new Semaphore(1);
}
public void printJob (Object document) {
try {
semaphore.acquire();
long duration = (long) (Math.random() * 10);
System.out.printf("%s: PrintQueue: Printing a Job during %d seconds\n", Thread.currentThread().getName(), duration);
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
public static void main (String args[]){
PrintQueue printQueue=new PrintQueue();
Thread thread[]=new Thread[10];
for (int i=0; i<10; i++){
thread[i]=new Thread(new Job(printQueue),"Thread"+i);
}
for (int i=0; i<10; i++){
thread[i].start();
}
}
}
class Job implements Runnable {
private PrintQueue printQueue;
public Job(PrintQueue printQueue){
this.printQueue=printQueue;
}
@Override
public void run() {
System.out.printf("%s: Going to print a job\n",Thread.currentThread().getName());
printQueue.printJob(new Object());
System.out.printf("%s: The document has been printed\n",Thread.currentThread().getName());
}
}
acquireUninterruptibly():忽略中断。正常acquire()方法或睡眠线程,在阻塞期间有可能被中断,此时会跑出InterruptedException 异常
tryAcquire(): 尝试获取资源,又返回true没有资源返回false不会阻塞
semaphores也有公平机制,默认非公平,可以构造器中指定
多个线程同时访问
public class PrintQueue {
private boolean freePrinters[];
private Lock lockPrinters;
private Semaphore semaphore;
public PrintQueue(){
semaphore=new Semaphore(3);
freePrinters=new boolean[3];
for (int i=0; i<3; i++){
freePrinters[i]=true;
}
lockPrinters=new ReentrantLock();
}
public void printJob (Object document){
try {
semaphore.acquire();
int assignedPrinter=getPrinter();
long duration=(long)(Math.random()*10);
System.out.printf("%s: PrintQueue: Printing a Job in Printer%d during %d seconds\n",Thread.currentThread().getName(),assignedPrinter,duration);
TimeUnit.SECONDS.sleep(duration);
freePrinters[assignedPrinter]=true;
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
private int getPrinter() {
int ret=-1;
try {
lockPrinters.lock();
for (int i=0; i<freePrinters.length; i++) {
if (freePrinters[i]){
ret=i;
freePrinters[i]=false;
break;
}
} } catch (Exception e) {
e.printStackTrace();
} finally {
lockPrinters.unlock();
}
return ret;
}
}
semaphore 控制三个线程同时运行,每个线程拥有一个print资源用完释放资源。
acquire(), acquireUninterruptibly(), tryAcquire(),release() 方法有个参数控制一次获得多少,例如acquire(int permits) ,不写permits默认是1
CountDownLatch
public class Videoconference implements Runnable {
private final CountDownLatch controller;
public Videoconference(int number) {
controller=new CountDownLatch(number);
}
public void arrive(String name){
System.out.printf("%s has arrived.",name);
controller.countDown();
System.out.printf("VideoConference: Waiting for %d participants.\n",controller.getCount());
}
@Override
public void run() {
System.out.printf("VideoConference: Initialization: %d participants.\n",controller.getCount());
try {
controller.await();
System.out.printf("VideoConference: All the participants have come\n");
System.out.printf("VideoConference: Let's start...\n");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Videoconference conference=new Videoconference(10);
Thread threadConference=new Thread(conference);
threadConference.start();
for (int i=0; i<10; i++){
Participant p=new Participant(conference, "Participant "+i);
Thread t=new Thread(p);
t.start();
}
}
}
class Participant implements Runnable {
private Videoconference conference;
private String name;
public Participant(Videoconference conference, String name) {
this.conference=conference;
this.name=name;
}
@Override
public void run() {
long duration=(long)(Math.random()*10);
try {
TimeUnit.SECONDS.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
conference.arrive(name);
}
}
CountDownLatch 有三个基本要素
1.初始化值决定CountDownLatch 类需要等待多少事件
2.await()方法,需要等待所有事件执行完才会执行的线程调用这个方法
3.countDown()方法,被结束的事件线程调用
CountDownLatch 只可以调用countDown()修改count
await(longtime,TimeUnitunit):count到达0或者指定时间到达执行
CyclicBarrier
public class MatrixMock {
private int data[][];
public MatrixMock(int size, int length, int number){
int counter=0;
data=new int[size][length];
Random random=new Random();
for (int i=0; i<size; i++) {
for (int j=0; j<length; j++){
data[i][j]=random.nextInt(10);
if (data[i][j]==number){
counter++;
}
}
}
System.out.printf("Mock: There are %d ocurrences of number in generated data.\n",counter,number);
}
public int[] getRow(int row){
if ((row>=0)&&(row<data.length)){
return data[row];
}
return null;
}
}
class Results {
private int data[];
public Results(int size){
data=new int[size];
}
public void setData(int position, int value){
data[position]=value;
}
public int[] getData(){
return data;
}
}
class Searcher implements Runnable {
private int firstRow;
private int lastRow;
private MatrixMock mock;
private Results results;
private int number;
private final CyclicBarrier barrier;
public Searcher(int firstRow, int lastRow, MatrixMock mock, Results results, int number, CyclicBarrier barrier){
this.firstRow=firstRow;
this.lastRow=lastRow;
this.mock=mock;
this.results=results;
this.number=number;
this.barrier=barrier;
}
@Override
public void run() {
int counter;
System.out.printf("%s: Processing lines from %d to %d.\n", Thread.currentThread().getName(), firstRow, lastRow);
for (int i = firstRow; i < lastRow; i++) {
int row[] = mock.getRow(i);
counter = 0;
for (int j = 0; j < row.length; j++) {
if (row[j] == number) {
counter++;
}
}
results.setData(i, counter);
}
System.out.printf("%s: Lines processed.\n", Thread.currentThread().getName());
try {
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
class Grouper implements Runnable {
private Results results;
public Grouper(Results results){
this.results=results;
}
@Override
public void run() {
int finalResult=0;
System.out.printf("Grouper: Processing results...\n");
int data[]=results.getData();
for (int number:data){
finalResult+=number;
}
System.out.printf("Grouper: Total result: %d.\n",finalResult);
}
public static void main(String[] args) {
final int ROWS=10000;
final int NUMBERS=1000;
final int SEARCH=5;
final int PARTICIPANTS=5;
final int LINES_PARTICIPANT=2000;
MatrixMock mock=new MatrixMock(ROWS, NUMBERS,SEARCH);
Results results=new Results(ROWS);
Grouper grouper=new Grouper(results);
CyclicBarrier barrier=new CyclicBarrier(PARTICIPANTS,grouper);
Searcher searchers[]=new Searcher[PARTICIPANTS];
for (int i=0; i<PARTICIPANTS; i++){
searchers[i]=new Searcher(i*LINES_PARTICIPANT, (i*LINES_PARTICIPANT)+LINES_PARTICIPANT, mock, results, 5,barrier);
Thread thread=new Thread(searchers[i]);
thread.start();
}
System.out.printf("Main: The main thread has finished.\n");
}
}
5个thread都执行完后,grouper线程会执行
CyclicBarrier 类初始化的时候 构造器有个int参数,指示多少个线程需要同步。当一个线程执行到某个点需要等待其他线程执行就调用await() 方法,此时该线程睡眠,直到其他线程到达。所有线程都到达await() 方法之后,这些线程才会继续执行
await(longtime,TimeUnitunit): 线程会睡眠直到被中断、时间到达或者CyclicBarrier到达
getNumberWaiting():等待中的线程数量
getParties():将要同步的线程数量
reset():重置到初始状态,等待中的线程会收到BrokenBarrierException 异常