并发编程15-并发工具

188 阅读3分钟

1.CountDownLatch

1.1 概述

1.1.1 简述

CountDownLatch的构造函数入参有N(int类型)个作为计数器;
然后起多子线程,子线程countDownLatch.countDown后计数-1;
主线程countDownLatch.await();
待计数为0后主线程countDownLatch.await()后面继续执行.

CountDownLatch latch = new CountDownLatch(lineCount); //公用对象

latch.countDown();  //子线程
latch.await();      //主线程

1.1.2 特性

  • 共享锁(计数只要不为0,所有线程都可以进),

  • CountDownLatch的构造函数接收一个int类型的参数作为计数器,如果你想等待N个点完成,这里就传入N;每一次调用CountDownLatch的CountDown的时候的计数器减为0的时候,CountDownLatch的await会阻塞当前线程,直到N变成零.

  • 由于countDown方法可以用在任何地方,所以这里说的N个点,可以是N个线程,也可以是1个线程里的N个执行步骤。用在多个线程时,你只需要把这个CountDownLatch的引用传递到线程里。

  • 其他方法 如果有某个解析sheet的线程处理的比较慢,我们不可能让主线程一直等待,所以我们可以使用另外一个带指定时间的await方法,await(long time, TimeUnit unit): 这个方法等待特定时间后,就会不再阻塞当前线程。join也有类似的方法。

  • 注意:计数器必须大于等于0,只是等于0时候,计数器就是零,调用await方法时不会阻塞当前线程。CountDownLatch不可能重新初始化或者修改CountDownLatch对象的内部计数器的值。一个线程调用countDown方法 happen-before 另外一个线程调用await方法。

1.2 示例

  • MultiCountUseCountDownLatch,FileTools

import java.util.List;
import java.util.concurrent.CountDownLatch;


/**
 * 实现,读一个文件,多行数字,
 * 然后多线程处理多行数字,
 * 所有线程都全部处理完之后,再最终累加每行计算的结果 得到总结果
 * 使用CountDownLatch来处理
 */
public class MultiCountUseCountDownLatch {

    private int[] nums;

    public MultiCountUseCountDownLatch(int line) {
        nums = new int[line];
    }

    public void calc(String line, int index, CountDownLatch latch) {
        String[] nus = line.split(","); // 切分出每个值
        int total = 0;
        for (String num : nus) {
            total += Integer.parseInt(num);
        }
        nums[index] = total; // 把计算的结果放到数组中指定的位置
        System.out.println(Thread.currentThread().getName() + " 执行计算任务... " + line + " 结果为:" + total);
        latch.countDown();
    }

    public void sum() {
        System.out.println("汇总线程开始执行... ");
        int total = 0;
        for (int i = 0; i < nums.length; i++) {
            total += nums[i];
        }
        System.out.println("最终的结果为:" + total);
    }

    /**
     * before latch.await
     Thread-2 执行计算任务... 23,45,67,78,89 结果为:302
     Thread-3 执行计算任务... 12,12 结果为:24
     Thread-1 执行计算任务... 21,12,18,45,11 结果为:107
     Thread-0 执行计算任务... 10,20,30,33,12,23 结果为:128
     after latch.await
     汇总线程开始执行...
     最终的结果为:561
     */
    public static void main(String[] args) {
        String filePath = FileTools.getPath();
        List<String> contents = FileTools.readFile(filePath);
        int lineCount = contents.size();

        CountDownLatch latch = new CountDownLatch(lineCount);//等待几个线程完成后集中处理.

        MultiCountUseCountDownLatch multiCountUseCountDownLatch = new MultiCountUseCountDownLatch(lineCount);
        for (int i = 0; i < lineCount; i++) {
            final int j = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    multiCountUseCountDownLatch.calc(contents.get(j), j, latch);
                }
            }).start();
        }

        System.out.println("before latch.await");
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("after latch.await");

        multiCountUseCountDownLatch.sum();
    }


}






import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class FileTools {

    //读文件行数,一行一个对象放在List<String>中
    public static List<String> readFile(String filePath) {
        List<String> contents = new ArrayList<>();
        String line = null;
        BufferedReader br = null;
        try {
            br = new BufferedReader(new FileReader(filePath+ File.separator+"nums.txt"));
            while ((line = br.readLine()) != null) {
                contents.add(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return contents;
    }

    //获取当前文件的所在的classpath路径
    public static String  getPath(){
        File directory = new File("");// 设定为当前文件夹
        String absolutePath= directory.getAbsolutePath();
        System.out.println("directory.getAbsolutePath()->" + absolutePath);
        Class c = MultiCountNotUseCountDownLatch.class;
        String packagePath = c.getPackage().getName();
        System.out.println("third.getPackage()->" + packagePath);
        packagePath =  packagePath.replace(".",File.separator);
        System.out.println("third.getPackage2()->" + packagePath);

        File file = new File(c.getResource("/").getPath());
        System.out.println("file.toString()->"+file.toString());

        String filePath = file.toString() + File.separator + packagePath;
        return  filePath;
    }
}



nums.txt 包含数据如下:
10,20,30,33,12,23
21,12,18,45,11
23,45,67,78,89
12,12


1.3 常用构造方法及方法

  • CountDownLatch(int count) 构造方法
  • countDown() 单个part线程执行完毕
  • await() 等待所有part线程完成
  • await(long timeout, TimeUnit unit)
  • getCount()

1.4 源码

  • CountDownLatch
package java.util.concurrent;
public class CountDownLatch {

    //构造方法,入口,输入待处理的线程计数器总个数,多个少线程就传给Sync,最终setState的值为线程个数. 
   public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }

   //释放statue-1,每countDown一次,计数器数字减1,
    public void countDown() {
        sync.releaseShared(1);
    }

    //当CountDownLatch中的线程的个数不为0时,一直等待;也就是countDown多次之后,计数器为0了,就不await()了
    //等待处理中..,一直等待,可中断的等待.这个在AQS中调用了tryAcquireShared.最终调用Sync的tryReleaseShared
    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

    //重构方法await
     public boolean await(long timeout, TimeUnit unit)
        throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }

   
  //查看统计线程个数
    public long getCount() {
        return sync.getCount();
    }

   private final Sync sync;

  //继承AQS的同步器,内部类,由于是共享锁,所以Acquire和Release都是Shared
   private static final class Sync extends AbstractQueuedSynchronizer {

	Sync(int count) {
            setState(count);
        }

        //状态为0了则返回1,否则-1
	protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }

	//释放1
	protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
                int c = getState();
		//如果状态为0,则不用释放,所以返回fasle
                if (c == 0)
                    return false;
                int nextc = c-1;
		//如果getState为1,则减-1,直到减到0,则返回true即(nextc==0)
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }

   }


public abstract class AbstractQueuedSynchronizer

   public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
	//根据tryAcquireShared的返回,如果<0,则加到等待队列中
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }

}  

2. CyclicBarrier

  • Cyclic /'saɪklɪk/ adj. 环的;循环的;周期的
  • Barrier /'bærɪɚ/ 障碍物,屏障;界线

2.1概述

2.1.1 简述

同步屏障:像开会,所有人(线程)到齐(先到的人(线程)等待)之后再执行一个总线程,然后总线程执行完之后还可以继续执行各自线程.

//主线程
 CyclicBarrier barrier = new CyclicBarrier(int parties, Runnable barrierAction) ;
 
 //子线程
  barrier.await();

2.1.2 特性

  • 同步屏障,所有的同步方法都到齐的时候,所有的等待方法就会被唤醒.

  • 让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。

  • 如果有一个线程在await()之前发生异常,则不会执行Barrier线程.

2.2 示例

  • CyclicBarrierThread
import java.util.Random;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierThread {
    Random random = new Random();


    public static void main(String[] args) {
        testCycliBarrierBasic();
    }


    /**
     * Thread-9 到达会议室,等待开会..
     Thread-8 到达会议室,等待开会..
     Thread-0 到达会议室,等待开会..
     Thread-7 到达会议室,等待开会..
     Thread-6 到达会议室,等待开会..
     Thread-2 到达会议室,等待开会..
     Thread-1 到达会议室,等待开会..
     Thread-5 到达会议室,等待开会..
     Thread-3 到达会议室,等待开会..
     Thread-4 到达会议室,等待开会..
     好!都到齐了,我们开始开会.....
     Thread-4 开始发言了..
     Thread-7 开始发言了..
     Thread-0 开始发言了..
     Thread-8 开始发言了..
     Thread-9 开始发言了..
     Thread-3 开始发言了..
     Thread-5 开始发言了..
     Thread-1 开始发言了..
     Thread-6 开始发言了..
     Thread-2 开始发言了..
     */
    //测试同步屏障基本功能
    public  static void testCycliBarrierBasic(){
        CyclicBarrierThread cyclicBarrierThread = new CyclicBarrierThread();

        //屏障到期后的执行内容
        CyclicBarrier barrier = new CyclicBarrier(10, new Runnable() {
            //10个独立的线程都执行完成后的执行该段
            @Override
            public void run() {
                System.out.println("好!都到齐了,我们开始开会.....");
            }
        });

        //10个各自执行的线程
        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    cyclicBarrierThread.barrierBasic(barrier);
                }
            }).start();
        }
    }


    //各多线程执行
    public void barrierBasic(CyclicBarrier barrier) {
        try {
            Thread.sleep(random.nextInt(4000));
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " 到达会议室,等待开会..");

        //各自统一等待,等待所有线程完成,然后再执行CyclicBarrier中的线程
        try {
            barrier.await();
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName() + " 开始发言了..");
    }
}
  • CyclicBarrierExceptionThread
import java.util.Random;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExceptionThread {
    Random random = new Random();


    public static void main(String[] args) {
        testCycliBarrierException();
    }

    /**
     * Thread-1 到达会议室,等待开会..
     Thread-5 到达会议室,等待开会..
     Thread-3 到达会议室,等待开会..
     Thread-8 到达会议室,等待开会..
     Thread-2 到达会议室,等待开会..
     Thread-7 到达会议室,等待开会..
     Exception in thread "Thread-7" java.lang.RuntimeException: 线程7异常了哟
     at course.threadstu.tb5.CyclicBarrierThread.meetingException(CyclicBarrierThread.java:86)
     at course.threadstu.tb5.CyclicBarrierThread$4.run(CyclicBarrierThread.java:114)
     at java.lang.Thread.run(Thread.java:745)
     Thread-4 到达会议室,等待开会..
     Thread-9 到达会议室,等待开会..
     Thread-6 到达会议室,等待开会..
     Thread-0 到达会议室,等待开会..

     当有一个线程异常的时候,就不会执行Barrier线程.
     */
    public  static void testCycliBarrierException(){
        CyclicBarrierExceptionThread cyclicBarrierExceptionThread = new CyclicBarrierExceptionThread();

        CyclicBarrier barrier = new CyclicBarrier(10, new Runnable() {
            //10个独立的线程都执行完成后的执行该段
            @Override
            public void run() {
                System.out.println("好!都到齐了,我们开始开会.....");
            }
        });

        
        //10个各自执行的线程
        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    cyclicBarrierExceptionThread.meetingException(barrier);
                }
            }).start();
        }
    }




    //各多线程执行,其中产生异常
    public void meetingException(CyclicBarrier barrier) {
        try {
            Thread.sleep(random.nextInt(4000));
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " 到达会议室,等待开会..");

        if (Thread.currentThread().getName().equals("Thread-7")) {
            throw new RuntimeException("线程7异常了哟");
        }
        //各自统一等待,等待所有线程完成,然后再执行CyclicBarrier中的线程
        try {
            barrier.await();
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName() + " 可以发言了..");
    }

}
  • CyclicBarrierResetThread

import java.util.Random;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierResetThread {
    Random random = new Random();


    public static void main(String[] args) {
        testCycliBarrierReset();
    }

    //测试同步屏障同步功能
    public static void testCycliBarrierReset(){
        CyclicBarrierResetThread cyclicBarrierThread = new CyclicBarrierResetThread();
        CyclicBarrier barrier = new CyclicBarrier(10, new Runnable() {
            //10个独立的线程都执行完成后的执行该段
            @Override
            public void run() {
                System.out.println("好!都到齐了,我们开始开会.....");
            }
        });

        //10个各自执行的线程
        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    cyclicBarrierThread.meetingReset(barrier);
                }
            }).start();
        }

        // 监控等待线程数
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("等待的线程数 " + barrier.getNumberWaiting());
                    System.out.println("is broken " + barrier.isBroken());
                }
            }
        }).start();
    }


    //各多线程执行
    public void meetingReset(CyclicBarrier barrier) {
        try {
            Thread.sleep(random.nextInt(4000));
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " 到达会议室,等待开会..");

        if (Thread.currentThread().getName().equals("Thread-7")) {
            // Thread.currentThread().interrupt();
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            barrier.reset();
        }

        //各自统一等待,等
        try {
            barrier.await();
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName() + " 可以发言了..");
    }
}

2.3 常用构造方法和方法

  • CyclicBarrier(int parties) 待屏障的线程个数

  • public CyclicBarrier(int parties, Runnable barrierAction) 屏障到达后执行

  • await() 屏障等待

  • reset() 会导致已经reset后的任务一直等待(reset会new Generation,导致broken为false,则后来线程的状态也不异常,一直等待),reset要慎用.即使待所有线程到达后再reset,要回造成调用reset的线程一直await();

  • isBroken() 是否中断

  • getNumberWaiting() 获取await等待中的线程数目

2.4 源码

//同步屏障,所有的同步方法都到齐的时候,所有的等待方法就会被唤醒. 
//如果一个线程发生interrupted,则已经到达的线程都会被notify(breakBarrier)
package java.util.concurrent;
public class CyclicBarrier {
    
    /** The number of parties */
    //计数值
    private final int parties;
    /* The command to run when tripped */
    //都达到的时候执行该事件.
    private final Runnable barrierCommand;

    private final ReentrantLock lock = new ReentrantLock();
    
    private final Condition trip = lock.newCondition(); 

    private Generation generation = new Generation();
    //还可以统计还剩余多少线程待执行
    private int count;
 
    //验证中断使用
    private static class Generation {
	//是否中断
        boolean broken = false;
    }

    //构造方法1
    /*
    创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,
    但它不会在启动 barrier 时执行预定义的操作。
    */
    public CyclicBarrier(int parties) {
        this(parties, null);
    }

    //构造方法2
    /*
    创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,
    并在启动 barrier 时执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行
    */
    public CyclicBarrier(int parties, Runnable barrierAction) {
        if (parties <= 0) throw new IllegalArgumentException();
        this.parties = parties;
        this.count = parties;
        this.barrierCommand = barrierAction;
    }


   public int await() throws InterruptedException, BrokenBarrierException {
        try {
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe); // cannot happen
        }
    }


    /**
     * Main barrier code, covering the various policies.
     */
   //核心代码,保证线程安全
    private int dowait(boolean timed, long nanos)
        throws InterruptedException, BrokenBarrierException,
               TimeoutException {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            final Generation g = generation;
	    //中断标志是否中断了.如果中断则异常,还有如果前面有一个线程中断则后来的线程会再这里抛异常.
            if (g.broken)
                throw new BrokenBarrierException();
	     //线程有没有被中断.则通过breakBarrier()[改变generation.brokend=true并唤醒所有已到达等待的线程]
            if (Thread.interrupted()) {
                breakBarrier();
                throw new InterruptedException();
            }

	    //count就是parties的,即partThread的个数
            int index = --count;
	    //如果等待线程为0了.则所有的part线程执行完毕,叫醒构造方法中的线程(如果有的话)
            if (index == 0) {  // tripped
                boolean ranAction = false;
                try {
                    final Runnable command = barrierCommand;
                    if (command != null)
                        command.run();//如果
                    ranAction = true;
		    //修改generation,标识是否执行完成.的叫醒时会用(所有的都叫醒)
                    nextGeneration();
                    return 0;
                } finally {
                    if (!ranAction)//如果command.run()时出现异常
                        breakBarrier();
                }
            }

            // loop until tripped, broken, interrupted, or timed out
	    //执行过程中,所有线程没有完全完成. 
            for (;;) {
                try {
		   //timed为false
                    if (!timed)
                        trip.await(); //即condition.await
                    else if (nanos > 0L)
                        nanos = trip.awaitNanos(nanos);
                } catch (InterruptedException ie) {
		    //发生中断异常时
		   //说明没被reset,且没被中断,则此时主动中断
                    if (g == generation && ! g.broken) {
                        breakBarrier();
                        throw ie;
		   //如果被中断了.	
                    } else {
                        // We're about to finish waiting even if we had not
                        // been interrupted, so this interrupt is deemed to
                        // "belong" to subsequent execution.
                        Thread.currentThread().interrupt();
                    }
                }
		//等待之后被叫醒执行以下三句.broken在线程间传递,还有如果是某个线程中断了则broken为true则抛异常
                if (g.broken)
                    throw new BrokenBarrierException();
		//说明被reset了或者完成(command.run())
                if (g != generation)
                    return index;
		//超时
                if (timed && nanos <= 0L) {
                    breakBarrier();
                    throw new TimeoutException();
                }
            }
        } finally {
            lock.unlock();
        }
    }

  //叫醒所有part线程
  private void nextGeneration() {
        // signal completion of last generation
        trip.signalAll();//所有的等待线程叫醒trip为Condition
        // set up next generation
        count = parties;  //然后count设置为初始值个数
        generation = new Generation(); //generation也重置,其实就broken为false
    }

   //打破屏障
   private void breakBarrier() {
        generation.broken = true;  //回归初始值
        count = parties;	//回归初始值	
        trip.signalAll();	//叫醒所有线程
    }


    //还支持reset,重置
    /
    public void reset() {
        final ReentrantLock lock = this.lock;
	//加锁
        lock.lock();
        try {
	   //此时
            breakBarrier();   // break the current generation
	    //由于一个new 一个 generation,所以broken为false,后来的线程不能抛异常,一直等待
            nextGeneration(); // start a new generation
        } finally {
            lock.unlock();
        }
    }
}

3. Semaphore

Semaphore: /'sɛməfɔr/ 信号;旗语;臂板信号机

3.1.概述

  • Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源 只有指定数目的线程可以执行.当多余该数据的线程时,其它线程等待,当前面有线程结束后,可以继续新的线程执行. 有点类似于线程池(ExecutorService threadPool = Executors.newFixedThreadPools(10))
  • Semaphore可以用于做流量控制,特别公用资源有限的应用场景,比如数据库连接
  • 多个线程进入,所以是共享锁.
//主线程
Semaphore semaphore = new Semaphore(10);

//子线程
semaphore.acquire();
semaphore.release();

3.2.示例

  • SemaphoreThread

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class SemaphoreThread {
	
	public void semaphoreExecute(Semaphore semaphore) {
		try {
			semaphore.acquire();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		System.out.println(Thread.currentThread().getName() + " is run ...");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		semaphore.release();
	}
	
	
	public static void main(String[] args) {
		
		SemaphoreThread semaphoreThread = new SemaphoreThread();
		Semaphore semaphore = new Semaphore(10);
		int i=0;
		while(i<100) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					semaphoreThread.semaphoreExecute(semaphore);
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}).start();
			i++;
		}

		//类似于如下功能,这个线程池中只有10个线程而SemaphoreThread只执行10个
		executors();
	}

	public static void executors(){
		ExecutorService threadPool = Executors.newFixedThreadPool(10);
		int j=0;
		while(j<100) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + " 执行...");
				}
			}).start();
			j++;
		}
	}

}

3.3.常用构造方法和方法

  • Semaphore(int permits) 构造方法,默认非公平
  • Semaphore(int permits, boolean fair) 可以构造共平;非公平
  • acquire() 获取
  • release() 释放

3.4.源码

package java.util.concurrent;
public class Semaphore implements java.io.Serializable {

   private final Sync sync;
  //内部类
   abstract static class Sync extends AbstractQueuedSynchronizer {
	Sync(int permits) {
            setState(permits);
        }

	//核心代码,就是判断一下当前是否还有可余量.如果还有则可以获取,如果没有则不能获取.
	 final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }

   }

  //构造方法1
   public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

  //构造方法2
   public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }

  //常用方法1
   public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

       

 //常用方法2
    public void release() {
        sync.releaseShared(1);
    }

   //内部类-不公平锁
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = -2694183684443567898L;

        NonfairSync(int permits) {
            super(permits);
        }

        protected int tryAcquireShared(int acquires) {
            return nonfairTryAcquireShared(acquires);
        }
    }

   //内部类-公平锁
     static final class FairSync extends Sync {
        private static final long serialVersionUID = 2014338818796000944L;

        FairSync(int permits) {
            super(permits);
        }

        protected int tryAcquireShared(int acquires) {
            for (;;) {
                if (hasQueuedPredecessors())
                    return -1;
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }
    }

}

3.5 参考文章

ifeve.com/concurrency…

4. Exchanger

Exchanger: /ɪks'tʃendʒər/ n.交换器;交易所;交换程序

4.1.概述

  • Exchanger 是一个用于线程间协作的工具类,Exchanger用于进行线程间的数据交换,它提供一个同步点,在这个同步点,两个线程可以交换彼此的数据。这两个线程通过exchange 方法交换数据,如果第一个线程先执行exchange 方法,它会一直等待第二个线程也执行exchange 方法,当两个线程都到达同步点时,这两个线程就可以交换数据

  • 偶数个线程成对出现,如果出现奇数个,则最后一个线程等待了.

  • 如果多个线程,则先到达的连续到达的两个数据交互,并且处理,然后后续再到达的两个再处理.也就是连续成对处理并清空

  • 使用场景: 彩票,多线程多网站抓数据. 依赖于多线程的结果数据,然后在比较结果. 没抓到可以设置超时时间.

  • 示例:4

//主线程
 Exchanger<String> exch = new Exchanger<>();
 
//子线程 
String value =exch.exchange(res);

4.2.示例

ExchangerThread

4.3.源码

package java.util.concurrent;
public class Exchanger<V> {
   public V exchange(V x) throws InterruptedException {
        Object v;
        Object item = (x == null) ? NULL_ITEM : x; // translate null args
        if ((arena != null ||
             (v = slotExchange(item, false, 0L)) == null) &&
            ((Thread.interrupted() || // disambiguates null return
              (v = arenaExchange(item, false, 0L)) == null)))
            throw new InterruptedException();
        return (v == NULL_ITEM) ? null : (V)v;
    }
}