JAVA的Synchronizer

一、闭锁:
可以延迟某一组或一个线程的执行到另一组或另一个线程运行至某一特定点,例如一个服务需要等待它所依赖的服务都已经开始、一个用于计算的线程需要等待另外几项资源准备完毕。CountDownLatch是实现类之一,在CountDownLatch类中,countDown方法用于将计数器减一,await方法则会在调用位置阻塞到计数器为0或者被Interrupt。

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author jianbinggouzi
 */
public class CountDownLatchTest {
    private CountDownLatch countDownLatch; 
   //仅仅为了将子线程的println()和CountDown()变为原子操作,便于观察
    private ReentrantLock lock = new ReentrantLock();
    
    public CountDownLatchTest(int n){
        this.countDownLatch = new CountDownLatch(n);
        new Thread(){
            public void run(){
                System.out.println("t1 start and wait");
                try {
                     //countDownLatch.await(3,TimeUnit.SECONDS);
                    countDownLatch.await();
                } catch (InterruptedException ex) {
                    Logger.getLogger(CountDownLatchTest.class.getName()).log(Level.SEVERE, null, ex);
                }
                System.out.println("t1 finish");
            }
        }.start();
        for(int i=0;i

二、信号量:
Semaphore,保存一个许可集,许可的数量在初始化时指出,acquire()用于获取一个许可,当许可为0时,会阻塞直到有一个许可或者被中断,release()用于释放一个许可,但这个方法并不与acquire()完全相反,当存在的许可数量恢复为初始数量后,再次调用relaese(),并不会阻塞,而是会添加一个许可,举个栗子:
Semaphore semaphore = new Semaphore(5);
System.out.println(semaphore.availablePermits()); //输出5
for(int i=0;i<5;i++)
semaphore.release(); //不会阻塞
System.out.println(semahore.avaliablePermits()); //输出10
用Semaphore实现一个生产者消费者模型:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.mycompany.java_async;

import java.util.Random;
import java.util.concurrent.Semaphore;

/**
 *
 * @author jianbinggouzi
 */
public class SemaphoreTest {
    //生产者
    private Semaphore semaphore1 ;
    //消费者
    private Semaphore semaphore2 ;
    
    private int n;
    
    public SemaphoreTest(int n){
       semaphore1 = new Semaphore(n);
       semaphore2 = new Semaphore(0);
       this.n = 0;
       for(int i=0;i<2;i++)
           new Maker().start();
       for(int i=0;i<6;i++)
           new Worker().start();
       //System.out.println(semaphore.availablePermits());
    }
    class Maker extends Thread{
        public void run(){

            while(true){
                
                try{
                    semaphore1.acquire();
                    n++;
                    semaphore2.release();
                    System.out.println(n);
                    Thread.sleep((new Random()).nextInt(200));
                }catch(Exception e){
                    e.printStackTrace();
                }


            }


            
        }
    }
    class Worker extends Thread{
        public void run(){

            while(true){
                try{
                    semaphore2.acquire();
                    n--;
                    semaphore1.release();
                    System.out.println(n);
                    Thread.sleep(200+(new Random()).nextInt(300));
                }catch(Exception e){
                    e.printStackTrace();
                }
                
            }

        }
    }
}

三、关卡:
CyclicBarrier,也叫做栅栏,也可以用于阻塞一组线程直到某些前导事件发生,但是与闭锁不同,CountDownLatch侧重于两组线程之间的等待,例如一组线程等待另外一组线程都到达某个点再继续运行,而CyclicBarrier侧重于同一组线程之间的等待,例如让一组线程中的所有子线程都到达某个点后,再继续运行。
CountDownLatch是减数计数器,CyclicBarrier是加数计数器,在使用中,两者不同的侧重点体现在:前者的await()函数仅仅会让等待的线程阻塞至计数器为0,而后者的await()被线程调用时,会将计数器加1,然后此线程阻塞到计数器的值等于初始化时所指定的起始值。所以CountDownLatch的await()函数需要写在等待的线程A中,CountDown()函数写在被等待的线程B中,B调用CountDown()将计数器减1,A线程则阻塞在await()函数直到计数器为0;CyclicBarrier中没有CountDown(),只有await(),写在需要互相等待的线程组中,线程们会阻塞直到其他所有的线程都运行到这个点后,再继续运行。
当然CyclicBarrier也可以实现CountDownLatch类似的功能,实例化CyclicBarrier实例的时候,可以指定一个Runnable类型的参数,当所有子线程都到达指定的点(即全部从调用await()时的阻塞状态转变为可运行状态)后,会运行这个Runnable实例,写一个测试类:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.mycompany.java_async;

import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author jianbinggouzi
 */
public class BarrierTest {
    
    private CyclicBarrier cyclicBarrier;
    
    private Thread[] threads;
    //为了多线程下调用System.out.println()能按顺序输出
    private ReentrantLock lock = new ReentrantLock();
    
    public BarrierTest(int n){
        
        cyclicBarrier = new CyclicBarrier(n,new Runnable(){
            public void run(){
                lock.lock();
                System.out.println("all of thread finish");
                lock.unlock();
            }
        }){
            @Override
            public int await() throws InterruptedException, BrokenBarrierException {
                lock.lock();
                //监控线程状态
                for(int i=0;i

通过覆写await()完成的线程状态监控,这样输出的结果可能不太准确,不知道还有别的什么办法。。。输出如下:
JAVA的Synchronizer_第1张图片

你可能感兴趣的:(java)