简介

Exchanger,并发工具类,用于线程间的数据交换。

使用

两个线程,两个缓冲区,一个线程往一个缓冲区里面填数据,另一个线程从另一个缓冲区里面取数据。当填数据的线程将缓冲区填满时,或者取数据的线程将缓冲区里的数据取空时,就主动向对方发起交换缓冲区的动作,而交换的时机是,一个缓冲区满,另一个缓冲区空。代码如下,很简单,没有加注释。

  1. public class FillAndEmpty {
  2. Exchanger<DataBuffer> exchanger = new Exchanger<DataBuffer>();
  3. DataBuffer initialEmptyBuffer = DataBuffer.allocate(1024);
  4. DataBuffer initialFullBuffer = DataBuffer.allocate(1024);
  5.  
  6. class FillingLoop implements Runnable {
  7. public void run() {
  8. DataBuffer currentBuffer = initialEmptyBuffer;
  9. try {
  10. while (currentBuffer != null) {
  11. addToBuffer(currentBuffer);
  12. if (currentBuffer.isFull()) {
  13. System.out.println("[FillingLoop](Before)" + currentBuffer);
  14. currentBuffer = exchanger.exchange(currentBuffer);
  15. System.out.println("[FillingLoop](After)" + currentBuffer);
  16. }
  17. }
  18. } catch (InterruptedException ex) {
  19. Thread.currentThread().interrupt();
  20. }
  21. }
  22. }
  23.  
  24. class EmptyingLoop implements Runnable {
  25. public void run() {
  26. DataBuffer currentBuffer = initialFullBuffer;
  27. try {
  28. while (currentBuffer != null) {
  29. takeFromBuffer(currentBuffer);
  30. if (currentBuffer.isEmpty()) {
  31. System.out.println("[EmptyingLoop](Before)" + currentBuffer);
  32. currentBuffer = exchanger.exchange(currentBuffer);
  33. System.out.println("[EmptyingLoop](After)" + currentBuffer);
  34. }
  35. }
  36. } catch (InterruptedException ex) {
  37. Thread.currentThread().interrupt();
  38. }
  39. }
  40. }
  41.  
  42. void start() {
  43. Thread fillingLoopThread = new Thread(new FillingLoop());
  44. Thread emptyingLoopThread = new Thread(new EmptyingLoop());
  45.  
  46. fillingLoopThread.start();
  47. emptyingLoopThread.start();
  48.  
  49. try {
  50. Thread.sleep(10);
  51. } catch (InterruptedException e) {
  52. // do nothing
  53. }
  54. fillingLoopThread.interrupt();
  55. emptyingLoopThread.interrupt();
  56. }
  57.  
  58. public void takeFromBuffer(DataBuffer buf) {
  59. buf.take();
  60. }
  61.  
  62. public void addToBuffer(DataBuffer buf) {
  63. buf.add(1);
  64. }
  65.  
  66. private static class DataBuffer {
  67. private final int[] buf;
  68. private final int size;
  69. private int index;
  70.  
  71. private DataBuffer(int size) {
  72. this.size = size;
  73. this.buf = new int[size];
  74. }
  75.  
  76. public static DataBuffer allocate(int size) {
  77. return new DataBuffer(size);
  78. }
  79.  
  80. public boolean isEmpty() {
  81. return index == 0;
  82. }
  83.  
  84. public boolean isFull() {
  85. return index == size - 1;
  86. }
  87.  
  88. public int take() {
  89. if (index > 0) {
  90. return buf[index--];
  91. }
  92.  
  93. return -1;
  94. }
  95.  
  96. public void add(int data) {
  97. if (index < size - 1) {
  98. buf[index++] = data;
  99. }
  100. }
  101. }
  102.  
  103. public static void main(String[] args) {
  104. FillAndEmpty fae = new FillAndEmpty();
  105. fae.start();
  106. }
  107. }

输出如下,交换前后,两个线程所持的数据缓冲区对调。(部分输出未给出)

  1. [EmptyingLoop](Before)com.luoluo.exchanger.FillAndEmpty$DataBuffer@1733c6a5
  2. [FillingLoop](Before)com.luoluo.exchanger.FillAndEmpty$DataBuffer@39bcfec1
  3. [FillingLoop](After)com.luoluo.exchanger.FillAndEmpty$DataBuffer@1733c6a5
  4. [EmptyingLoop](After)com.luoluo.exchanger.FillAndEmpty$DataBuffer@39bcfec1
  5. ......

源码解析

常量介绍

  1. private static final int ASHIFT = 7; // 两个有效槽(slot -> Node)之间的字节地址长度(内存地址,以字节为单位),1 << 7至少为缓存行的大小,防止伪共享
  2. private static final int MMASK = 0xff; // 场地(一排槽,arena -> Node[])的可支持的最大索引,可分配的大小为 MMASK + 1
  3. private static final int SEQ = MMASK + 1; // bound的递增单元,确立其唯一性
  4. private static final int NCPU = Runtime.getRuntime().availableProcessors(); // CPU的个数,用于场地大小和自旋控制
  5. static final int FULL = (NCPU >= (MMASK << 1)) ? MMASK : NCPU >>> 1; // 最大的arena索引
  6. private static final int SPINS = 1 << 10; // 自旋次数,NCPU = 1时,禁用
  7. private static final Object NULL_ITEM = new Object();// 空对象,对应null
  8. private static final Object TIMED_OUT = new Object();// 超时对象,对应timeout

ASHIFT,两个有效的槽之间的地址长度是1 << 7(至少为缓存行的大小,避免伪共享问题,见下面说明)

MMASK,多槽交换可支持的最大索引,大小为MMASK + 1(index从0开始)

SEQ,bound的递增单元,确定其唯一性(高位)

NCPU,CPU的个数

FULL,最大的arena索引,不大于MMASK;arena,一排slot,为的是获得良好的伸缩性,避免所有的线程争用同一个槽位。

SPINS,自旋次数,用于自旋等待,是最轻量的等待,依次是 spin -> yield -> block

伪共享,高速缓存与内存之间是以缓存行为单位交换数据的,根据局部性原理,相邻地址空间的数据会被加载到高速缓存的同一个数据块上(缓存行),而数组是连续的(逻辑,涉及到虚拟内存)内存地址空间,因此,多个slot会被加载到同一个缓存行上,当一个slot改变时,会导致这个slot所在的缓存行上所有的数据(包括其他的slot)无效,需要从内存重新加载,影响性能。

所以,为了避免这种情况,需要填充数据,使得有效的slot不被加载到同一个缓存行上。填充的大小即为1 << 7,如下图所示

数据结构Node

  1. static final class Node {
  2. int index; // arena的索引
  3. int bound; // 记录上次的bound
  4. int collides; // 当前bound下CAS失败的次数
  5. int hash; // 伪随机,用于自旋
  6. Object item; // 当前线程携带的数据
  7. volatile Object match; // 存放释放线程携带的数据
  8. volatile Thread parked; // 挂在此结点上阻塞着的线程
  9. }

index,arena的索引

bound,记录上次的bound

collides,当前bound下CAS失败的次数,最大为m,m(bound & MMASK)为当前bound下最大有效索引,从右往左遍历,等到collides == m时,有效索引的槽位也已经遍历完了,这时需要增长槽位,增长的方式是重置bound(依赖SEQ更新其版本,高位;+1,低位),同时collides重置

hash,伪随机,用于自旋

item,当前线程携带的数据

match,存放释放线程(来交换的线程)携带的数据

parked,挂在此结点上阻塞着的线程,等待被释放

见下图

数据结构Participant

  1. // 每个线程携带一个Node
  2. static final class Participant extends ThreadLocal<Node> {
  3. public Node initialValue() {
  4. return new Node();
  5. }
  6. }

Participant直接继承自ThreadLocal保存当前线程携带的Node,交换操作主要依赖Node的行为

属性介绍

  1. private final Participant participant;// 每个线程携带一个Node
  2. private volatile Node[] arena; // 场地,Node数组
  3. private volatile Node slot;// 槽,单个Node
  4. private volatile int bound;// 当前最大有效arena索引,高8位+SEQ确立其唯一性,低8位记录有效索引

bound,记录最大有效的arena索引,动态变化,竞争激烈时(槽位全满)增加, 槽位空旷时减小。bound + SEQ +/- 1,其高位+ 1(SEQ,oxff + 1)确定其版本唯一性(比如,+1后,又-1,实际上是两个版本的bound,collides要重置的,而且从右向左遍历的索引也要更新,一般来讲,左边槽位比右边槽位竞争激烈,所以要从右向左找,为的是快速找到一个空位置,并尝试占领它,当bound加一又减一后,遍历索引右侧的槽位应该就空出来了,因为大家都往左边靠拢,所以要更新到最右侧,如果没有bound的版本唯一性,便没有索引更新,就一直往左遍历竞争激烈的槽位,还会误判,本来bound应该缩减的,反而又使其增加,于是会很影响效率的。),低位+/-1实际有效的索引(&MMASK)

如下图

exchange方法

  1. public V exchange(V x) throws InterruptedException {
  2. Object v;
  3. Object item = (x == null) ? NULL_ITEM : x; // 转换成空对象
  4. // arena == null, 路由到slotExchange(单槽交换), 如果arena != null或者单槽交换失败,且线程没有被中断,则路由到arenaExchange(多槽交换),返回null,则抛出中断异常
  5. if ((arena != null || (v = slotExchange(item, false, 0L)) == null)
  6. && ((Thread.interrupted() || (v = arenaExchange(item, false, 0L)) == null)))
  7. throw new InterruptedException();
  8. return (v == NULL_ITEM) ? null : (V) v;
  9. }

首先判断arena是否为null,如果为null,则调用slotExchange方法,如果arena不为null,或者slotExchange方法返回null,然后判断当前线程是否被中断(中断标记),有则抛出中断异常,没有则继续调用arenaExchange方法,如果该方法返回null,抛出中断异常,最后返回结果。

带超时的exchange方法

  1. public V exchange(V x, long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
  2. Object v;
  3. Object item = (x == null) ? NULL_ITEM : x;// 转换成空对象
  4. long ns = unit.toNanos(timeout);
  5. // arena == null, 路由到slotExchange(单槽交换), 如果arena != null或者单槽交换失败,且线程没有被中断,则路由到arenaExchange(多槽交换),返回null,则抛出中断异常
  6. if ((arena != null || (v = slotExchange(item, true, ns)) == null)
  7. && ((Thread.interrupted() || (v = arenaExchange(item, true, ns)) == null)))
  8. throw new InterruptedException();
  9. if (v == TIMED_OUT)// 超时
  10. throw new TimeoutException();
  11. return (v == NULL_ITEM) ? null : (V) v;
  12. }

同上,加了超时的判断。

slotExchange方法

  1. private final Object slotExchange(Object item, boolean timed, long ns) {
  2. Node p = participant.get(); // 获取当前线程携带的Node
  3. Thread t = Thread.currentThread(); // 当前线程
  4. if (t.isInterrupted()) // 保留中断状态,以便调用者可以重新检查,Thread.interrupted() 会清除中断状态标记
  5. return null;
  6. for (Node q;;) {
  7. if ((q = slot) != null) { // slot不为null, 说明已经有线程在这里等待了
  8. if (U.compareAndSwapObject(this, SLOT, q, null)) { // 将slot重新设置为null, CAS操作
  9. Object v = q.item; // 取出等待线程携带的数据
  10. q.match = item; // 将当前线程的携带的数据交给等待线程
  11. Thread w = q.parked; // 可能存在的等待线程(可能中断,不等了)
  12. if (w != null)
  13. U.unpark(w); // 唤醒等待线程
  14. return v; // 返回结果,交易成功
  15. }
  16. // CPU的个数多于1个,并且bound为0时创建 arena,并将bound设置为SEQ大小
  17. if (NCPU > 1 && bound == 0 && U.compareAndSwapInt(this, BOUND, 0, SEQ))
  18. arena = new Node[(FULL + 2) << ASHIFT]; // 根据CPU的个数估计Node的数量
  19. } else if (arena != null)
  20. return null; // 如果slot为null, 但arena不为null, 则转而路由到arenaExchange方法
  21. else { // 最后一种情况,说明当前线程先到,则占用此slot
  22. p.item = item; // 将携带的数据卸下,等待别的线程来交易
  23. if (U.compareAndSwapObject(this, SLOT, null, p)) // 将slot的设为当前线程携带的Node
  24. break; // 成功则跳出循环
  25. p.item = null; // 失败,将数据清除,继续循环
  26. }
  27. }
  28. // 当前线程等待被释放, spin -> yield -> block/cancel
  29. int h = p.hash; // 伪随机,用于自旋
  30. long end = timed ? System.nanoTime() + ns : 0L; // 如果timed为true,等待超时的时间点; 0表示没有设置超时
  31. int spins = (NCPU > 1) ? SPINS : 1; // 自旋次数
  32. Object v;
  33. while ((v = p.match) == null) { // 一直循环,直到有线程来交易
  34. if (spins > 0) { // 自旋,直至spins不大于0
  35. h ^= h << 1; // 伪随机算法, 目的是等h小于0(随机的)
  36. h ^= h >>> 3;
  37. h ^= h << 10;
  38. if (h == 0) // 初始值
  39. h = SPINS | (int) t.getId();
  40. else if (h < 0 && (--spins & ((SPINS >>> 1) - 1)) == 0)
  41. Thread.yield(); // 等到h < 0, 而spins的低9位也为0(防止spins过大,CPU空转过久),让出CPU时间片,每一次等待有两次让出CPU的时机(SPINS >>> 1)
  42. } else if (slot != p) // 别的线程已经到来,正在准备数据,自旋等待一会儿,马上就好
  43. spins = SPINS;
  44. // 如果线程没被中断,且arena还没被创建,并且没有超时
  45. else if (!t.isInterrupted() && arena == null && (!timed || (ns = end - System.nanoTime()) > 0L)) {
  46. U.putObject(t, BLOCKER, this); // 设置当前线程将阻塞在当前对象上
  47. p.parked = t; // 挂在此结点上的阻塞着的线程
  48. if (slot == p)
  49. U.park(false, ns); // 阻塞, 等着被唤醒或中断
  50. p.parked = null; // 醒来后,解除与结点的联系
  51. U.putObject(t, BLOCKER, null); // 解除阻塞对象
  52. } else if (U.compareAndSwapObject(this, SLOT, p, null)) { // 超时或其他(取消),给其他线程腾出slot
  53. v = timed && ns <= 0L && !t.isInterrupted() ? TIMED_OUT : null;
  54. break;
  55. }
  56. }
  57. // 归位
  58. U.putOrderedObject(p, MATCH, null);
  59. p.item = null;
  60. p.hash = h;
  61. return v;
  62. }

总结

1. 检查slot是否为空(null),不为空,说明已经有线程在此等待,尝试占领该槽位,如果占领成功,与等待线程交换数据,并唤醒等待线程,交易结束,返回。

2. 如果占领槽位失败,创建arena,但要继续【步骤1】尝试抢占slot,直至slot为空,或者抢占成功,交易结束返回。

3. 如果slot为空,则判断arena是否为空,如果arena不为空,返回null,重新路由到arenaExchange方法

4. 如果arena为空,说明当前线程是先到达的,尝试占有slot,如果成功,将slot标记为自己占用,跳出循环,继续【步骤5】,如果失败,则继续【步骤1】

5 当前线程等待被释放,等待的顺序是先自旋(spin),不成功则让出CPU时间片(yield),最后还不行就阻塞(block),spin -> yield -> block

6. 如果超时(设置超时的话)或被中断,则退出循环。

7. 最后,重置数据,下次重用,返回结果,结束。

见下图

arenaExchange方法

  1. private final Object arenaExchange(Object item, boolean timed, long ns) {
  2. Node[] a = arena; // 交换场地,一排slot
  3. Node p = participant.get(); // 获取当前线程携带的Node
  4. for (int i = p.index;;) { // arena的索引,数组下标
  5. int b, m, c;
  6. long j; // 原数组偏移量,包括填充值
  7. // 从场地中选出偏移地址为(i << ASHIFT) + ABASE的内存值,也即真正可用的Node
  8. Node q = (Node) U.getObjectVolatile(a, j = (i << ASHIFT) + ABASE);
  9. if (q != null && U.compareAndSwapObject(a, j, q, null)) { // 此槽位不为null, 说明已经有线程在这里等了,重新将其设置为null, CAS操作
  10. Object v = q.item; // 取出等待线程携带的数据
  11. q.match = item; // 将当前线程携带的数据交给等待线程
  12. Thread w = q.parked; // 可能存在的等待线程
  13. if (w != null)
  14. U.unpark(w); // 唤醒等待线程
  15. return v; // 返回结果, 交易成功
  16. } else if (i <= (m = (b = bound) & MMASK) && q == null) { // 有效交换位置,且槽位为空
  17. p.item = item; // 将携带的数据卸下,等待别的线程来交易
  18. if (U.compareAndSwapObject(a, j, null, p)) { // 槽位占领成功
  19. long end = (timed && m == 0) ? System.nanoTime() + ns : 0L; // 计算出超时结束时间点
  20. Thread t = Thread.currentThread(); // 当前线程
  21. for (int h = p.hash, spins = SPINS;;) { // 一直循环,直到有别的线程来交易,或超时,或中断
  22. Object v = p.match; // 检查是否有别的线程来交换数据
  23. if (v != null) { // 有则返回
  24. U.putOrderedObject(p, MATCH, null); // match重置,等着下次使用
  25. p.item = null; // 清空,下次接着使用
  26. p.hash = h;
  27. return v; // 返回结果,交易结束
  28. } else if (spins > 0) { // 自旋
  29. h ^= h << 1;
  30. h ^= h >>> 3;
  31. h ^= h << 10; // 移位加异或,伪随机
  32. if (h == 0) // 初始值
  33. h = SPINS | (int) t.getId();
  34. else if (h < 0 && // SPINS >>> 1, 一半的概率
  35. (--spins & ((SPINS >>> 1) - 1)) == 0)
  36. Thread.yield(); // 每一次等待有两次让出CPU的时机
  37. } else if (U.getObjectVolatile(a, j) != p)
  38. spins = SPINS; // 别的线程已经到来,正在准备数据,自旋等待一会儿,马上就好
  39. else if (!t.isInterrupted() && m == 0 && (!timed || (ns = end - System.nanoTime()) > 0L)) {
  40. U.putObject(t, BLOCKER, this); // 设置当前线程将阻塞在当前对象上
  41. p.parked = t; // 挂在此结点上的阻塞着的线程
  42. if (U.getObjectVolatile(a, j) == p)
  43. U.park(false, ns); // 阻塞, 等着被唤醒或中断
  44. p.parked = null; // 醒来后,解除与结点的联系
  45. U.putObject(t, BLOCKER, null); // 解除阻塞对象
  46. } else if (U.getObjectVolatile(a, j) == p && U.compareAndSwapObject(a, j, p, null)) {
  47. if (m != 0) // 尝试缩减
  48. U.compareAndSwapInt(this, BOUND, b, b + SEQ - 1); // 更新bound, 高位递增,低位 -1
  49. p.item = null; // 重置
  50. p.hash = h;
  51. i = p.index >>>= 1; // 索引减半,为的是快速找到汇合点(最左侧)
  52. if (Thread.interrupted())// 保留中断状态,以便调用者可以重新检查,Thread.interrupted() 会清除中断状态标记
  53. return null;
  54. if (timed && m == 0 && ns <= 0L) // 超时
  55. return TIMED_OUT;
  56. break; // 重新开始
  57. }
  58. }
  59. } else
  60. p.item = null; // 重置
  61. } else {
  62. if (p.bound != b) { // 别的线程更改了bound,重置collides为0, i的情况如下:当i != m, 或者m = 0时,i = m; 否则,i = m-1; 从右往左遍历
  63. p.bound = b;
  64. p.collides = 0;
  65. i = (i != m || m == 0) ? m : m - 1; // index 左移
  66. } else if ((c = p.collides) < m || m == FULL || !U.compareAndSwapInt(this, BOUND, b, b + SEQ + 1)) { // 更新bound, 高位递增,低位 +1
  67. p.collides = c + 1;
  68. i = (i == 0) ? m : i - 1; // 左移,遍历槽位,m == FULL时,i == 0(最左侧),重置i = m, 重新从右往左循环遍历
  69. } else
  70. i = m + 1; // 槽位增长
  71. p.index = i;
  72. }
  73. }
  74. }

总结

1. 从场地中选出偏移地址为(i << ASHIFT) + ABASE的内存值,也即第i个真正可用的Node,判断其槽位是否为空,为空,进入【步骤2】;不为空,说明有线程在此等待,尝试抢占该槽位,抢占成功,交换数据,并唤醒等待线程,返回,结束;没有抢占成功,进入【步骤9】

2. 检查索引(i vs m)是否越界,越界,进入【步骤9】;没有越界,进入下一步。

3. 尝试占有该槽位,抢占失败,进入【步骤1】;抢占成功,进入下一步。

4. 检查match,是否有线程来交换数据,如果有,交换数据,结束;如果没有,进入下一步。

5. 检查spin是否大于0,如果不大于0,进入下一步;如果大于0,检查hash是否小于0,并且spin减半或为0,如果不是,进入【步骤4】;如果是,让出CPU时间,过一会儿,进入【步骤4】

6. 检查是否中断,m达到最小值,是否超时,如果没有中断,没有超时,并且m达到最小值,阻塞,过一会儿进入【步骤4】;否则,下一步。

7. 没有线程来交换数据,尝试丢弃原有的槽位重新开始,丢弃失败,进入【步骤4】;否则,下一步。

8. bound减1(m>0),索引减半;检查是否中断或超时,如果没有,进入【步骤1】;否则,返回,结束。

9. 检查bound是否发生变化,如果变化了,重置collides,索引重置为m或左移,转向【步骤1】;否则,进入下一步。

10. 检查collides是否达到最大值,如果没有,进入【步骤13】,否则下一步。

11. m是否达到FULL,是,进入【步骤13】;否则,下一步。

12. CAS bound加1是否成功,如果成功,i置为m+1,槽位增长,进入【步骤1】;否则,下一步。

13. collides加1,索引左移,进入【步骤1】

见下图(看不清图片?鼠标放在图片上面,【右键】 -> 【在新标签页中打开图片(I)】 -> 【点击(+)矢量放大】)

Unsafe

  1. private static final sun.misc.Unsafe U;
  2. private static final long BOUND;
  3. private static final long SLOT;
  4. private static final long MATCH;
  5. private static final long BLOCKER;
  6. private static final int ABASE;
  7. static {
  8. int s;
  9. try {
  10. U = sun.misc.Unsafe.getUnsafe();
  11. Class<?> ek = Exchanger.class;
  12. Class<?> nk = Node.class;
  13. Class<?> ak = Node[].class;
  14. Class<?> tk = Thread.class;
  15. BOUND = U.objectFieldOffset(ek.getDeclaredField("bound"));
  16. SLOT = U.objectFieldOffset(ek.getDeclaredField("slot"));
  17. MATCH = U.objectFieldOffset(nk.getDeclaredField("match"));
  18. BLOCKER = U.objectFieldOffset(tk.getDeclaredField("parkBlocker"));
  19. s = U.arrayIndexScale(ak); // 数组增量地址
  20. ABASE = U.arrayBaseOffset(ak) + (1 << ASHIFT); // 数组首元素偏移地址
  21. } catch (Exception e) {
  22. throw new Error(e);
  23. }
  24. if ((s & (s - 1)) != 0 || s > (1 << ASHIFT))
  25. throw new Error("Unsupported array scale");
  26. } 

s为数组中每个元素占用的地址空间大小,ABASE为数组首元素偏移地址,防止伪共享

最后,arena = new Node[(FULL + 2) << ASHIFT],FULL,<= MMASK,scale,<= 1 << ASHIFT,说明(FULL + 2)<< ASHIFT 个Node,真正可用的是FULL + 2个,实际上是FULL + 1 个,最后一个没有用,也是为了防止伪共享,如果最后一个也使用,那么,其右边并没有填充,别的数据修改可能会影响到它,也即是发生伪共享问题。最大的有效索引是MMASK(bound & MMASK),但m(实际的最大索引)增长到FULL时,不再增长,会循环遍历槽位,尝试交换数据。

伪随机

h ^= h << 1; h ^= h >>> 3; h ^= h << 10;

实际上是xorshift算法,T = (I + La)(I + Rb)(I + Lc),其中,L代表左移,R代表右移,a, b, c分别代表上式的1,3,10,I代表矩阵{0,1}共32位(int),也即是二进制int,T代表的就是随机算法。翻译过来就是上面的式子:h ^= h << 1; h ^= h >>> 3; h ^= h << 10.

为什么要选用1,3,10呢?

其实,伪随机数,并不是真正的随机,而是通过算法模拟出来的,为了达到随机的效果,希望是周期越大越好。所谓周期指的是,当给定一个输入,得到的输出再作为下一次的输入,如此反复,直到某次输出恰巧等于最初的输入,可以作为随机算法关于随机数的周期。有了这个概念,我们就可以写代码测试下。

直观地推测,int类型最大周期应该是遍历该类型所有的值(0除外,【奇异矩阵】,如果是0的话,输出便一直是0,谈不上随机了),即是max - min = 232 - 1

Java代码

  1. public class PseudoRandom {
  2. private static final Map<Long, StringBuilder> map = new ConcurrentHashMap<>();
  3.  
  4. public static void random(int a, int b, int c) {
  5. long cnt = 0;
  6. int h = 1;
  7. do {
  8. h ^= h << a;
  9. h ^= h >>> b;
  10. h ^= h << c;
  11. cnt++;
  12. } while (h != 1);
  13.  
  14. StringBuilder builder = map.get(cnt);
  15. if (builder == null) {
  16. builder = new StringBuilder();
  17. map.put(cnt, builder);
  18. }
  19.  
  20. builder.append(" (" + a + ", " + b + ", " + c + ")");
  21. }
  22.  
  23. public static void main(String[] args) {
  24. CountDownLatch latch = new CountDownLatch(11 * 11 * 11);
  25. ExecutorService s = Executors.newFixedThreadPool(10);
  26. for (int i = 1; i < 11; i++) { // i, j ,k实际上应该是31,这里仅为了说明问题,当改成31时,CountDownLatch应该初始化为31 * 31 * 31
  27. for (int j = 1; j < 11; j++) {
  28. for (int k = 1; k < 11; k++) {
  29. final int ii = i;
  30. final int jj = j;
  31. final int kk = k;
  32. s.execute(new Runnable() {
  33. @Override
  34. public void run() {
  35. random(ii, jj, kk);
  36. latch.countDown();
  37. }
  38. });
  39. }
  40. }
  41. }
  42.  
  43. s.shutdown();
  44. try {
  45. latch.await(300, TimeUnit.SECONDS);
  46. } catch (InterruptedException e) {
  47. Thread.currentThread().interrupt();
  48. }
  49.  
  50. TreeMap<Long, StringBuilder> t = new TreeMap<Long, StringBuilder>(Collections.reverseOrder());
  51. t.putAll(map);
  52.  
  53. for (Map.Entry<Long, StringBuilder> entry : t.entrySet()) {
  54. System.out.println("[" + entry.getKey() + "]" + entry.getValue().toString());
  55. }
  56. }
  57. }

输出,按周期次数倒序排列,即最大的在前

  1. [4294967295] (1, 3, 10) (2, 7, 7) (2, 7, 9) (5, 9, 7) (7, 1, 9) (7, 7, 2) (7, 9, 5)
  2. [4160749537] (1, 7, 9) (4, 1, 9) (6, 5, 9)
  3. [3900702255] (1, 3, 4) (5, 5, 7) (7, 5, 5)
  4. [3758096377] (1, 9, 2) (2, 9, 1) (7, 7, 9)
  5. [2147483647] (1, 5, 5) (1, 9, 6) (2, 5, 5) (2, 5, 7) (5, 5, 1) (5, 5, 2) (6, 5, 7) (6, 9, 1) (7, 5, 2) (7, 5, 6)
  6. [2147483644] (1, 9, 10)
  7. [2147213313] (2, 5, 3) (3, 5, 2)
  8. [2147188740] (4, 5, 5) (4, 9, 1) (5, 5, 4)
  9. [2145385473] (7, 9, 9)
  10. [2145382404] (1, 5, 9)
  11. [2143288833] (5, 1, 6) (6, 1, 5)
  12. [2139094020] (1, 7, 6)
  13. [2113929153] (1, 5, 4) (4, 5, 1)
  14. [2080374753] (2, 3, 3) (3, 3, 2)
  15. [1997533470] (2, 9, 9)
  16. [1879048185] (2, 5, 9) (4, 7, 9)
  17. [1747831785] (8, 9, 5)
  18. [1610612733] (7, 3, 10)
  19. [1560280902] (3, 5, 5) (5, 5, 3)
  20. [1431655765] (1, 7, 7) (2, 9, 5) (5, 1, 8) (5, 9, 2) (7, 7, 1) (8, 1, 5)
  21. [1431562923] (1, 1, 2) (2, 1, 1)
  22. [1430257323] (3, 9, 7) (7, 9, 3)
  23. [1409286123] (5, 3, 7) (7, 3, 5) (9, 1, 10)
  24. [1339553285] (1, 9, 5) (5, 9, 1)
  25. [1242911789] (3, 7, 10) (5, 3, 10)
  26. [1174405085] (1, 3, 5) (5, 3, 1) (9, 3, 4)
  27. [1073741823] (3, 1, 6) (6, 1, 3)
  28. [1073594370] (1, 9, 4)
  29. [1064182911] (4, 3, 7) (7, 3, 4)
  30. [1006632930] (3, 1, 10)
  31. [714429611] (3, 1, 4) (4, 1, 3)
  32. [713031595] (1, 7, 5) (5, 7, 1) (7, 7, 10)
  33. [704642988] (3, 9, 10)
  34. [626349395] (9, 5, 3)
  35. [621455450] (2, 3, 9)
  36. [613543351] (1, 5, 3) (3, 5, 1)
  37. [602795529] (1, 1, 9) (7, 3, 9) (9, 1, 1) (9, 3, 7)
  38. [536870911] (3, 5, 7) (6, 9, 7) (7, 5, 3) (7, 9, 6)
  39. [536772612] (1, 1, 3)
  40. [534773505] (6, 7, 1)
  41. [528482241] (8, 3, 9)
  42. [520093634] (1, 5, 10)
  43. [469762041] (1, 7, 4) (4, 1, 7) (7, 1, 4)
  44. [459276069] (4, 7, 5)
  45. [453248985] (1, 3, 7)
  46. [429286605] (5, 7, 6) (6, 7, 5)
  47. [426141261] (1, 3, 8) (8, 3, 1)
  48. [390070086] (1, 1, 6)
  49. [389118324] (3, 3, 10)
  50. [352321494] (6, 7, 9)
  51. [352106517] (3, 7, 5) (5, 7, 3)
  52. [341310837] (8, 7, 1)
  53. [335544315] (4, 9, 7) (7, 7, 8) (7, 9, 4) (8, 7, 7)
  54. [335360010] (3, 9, 5)
  55. [310727725] (9, 3, 2)
  56. [286331153] (5, 3, 8) (8, 3, 5)
  57. [268435455] (1, 9, 3) (3, 9, 1)
  58. [268435454] (3, 1, 8) (7, 9, 8) (8, 9, 7)
  59. [268435452] (3, 1, 7) (7, 1, 3)
  60. [268435448] (2, 3, 7)
  61. [267386370] (5, 7, 7) (7, 7, 5)
  62. [260046817] (4, 3, 1)
  63. [259507262] (9, 5, 5)
  64. [252645135] (3, 1, 5) (5, 1, 3)
  65. [249690255] (5, 9, 8)
  66. [234637326] (4, 1, 5)
  67. [201326586] (5, 3, 6) (5, 7, 9) (6, 3, 5)
  68. [201222147] (3, 7, 8) (8, 7, 3)
  69. [195225786] (8, 1, 7)
  70. [178924204] (3, 1, 1)
  71. [167772155] (4, 3, 9)
  72. [167680005] (5, 9, 3)
  73. [153391689] (1, 5, 2) (2, 5, 1)
  74. [153092023] (5, 7, 4)
  75. [142501905] (2, 3, 5) (5, 3, 2)
  76. [134217727] (8, 1, 3)
  77. [134217726] (7, 5, 8)
  78. [134150145] (3, 7, 9)
  79. [134085633] (3, 7, 6) (6, 7, 3)
  80. [133693185] (1, 9, 7) (7, 9, 1)
  81. [129753631] (3, 9, 4) (4, 9, 3) (5, 5, 9)
  82. [117318663] (5, 1, 4)
  83. [100663293] (8, 9, 9)
  84. [97612893] (7, 1, 8)
  85. [97517382] (1, 7, 8)
  86. [94371795] (1, 7, 3) (3, 7, 1)
  87. [93323175] (6, 1, 7) (7, 1, 6)
  88. [89478485] (3, 5, 9)
  89. [87951402] (5, 9, 10)
  90. [82993665] (4, 3, 5) (5, 3, 4)
  91. [78212442] (1, 7, 10) (7, 5, 9) (9, 5, 7)
  92. [75497463] (9, 3, 8)
  93. [69273666] (7, 5, 1)
  94. [67108863] (4, 7, 1) (5, 9, 9)
  95. [67108862] (7, 3, 2)
  96. [67084290] (9, 5, 10)
  97. [66584449] (9, 3, 10)
  98. [66059784] (4, 5, 9) (9, 5, 4)
  99. [65536191] (2, 1, 5) (5, 1, 2)
  100. [65011681] (6, 1, 1)
  101. [62914530] (1, 7, 2) (2, 7, 1)
  102. [58260615] (2, 9, 3) (3, 9, 2)
  103. [57252195] (3, 5, 4) (4, 5, 3)
  104. [56884380] (1, 1, 5) (5, 1, 1)
  105. [55050135] (3, 1, 9) (9, 1, 3)
  106. [47439707] (1, 5, 8) (8, 5, 1)
  107. [44739242] (8, 5, 7)
  108. [42105595] (1, 9, 8) (8, 9, 1)
  109. [41287365] (5, 9, 6)
  110. [34636833] (1, 3, 6) (1, 5, 7) (6, 3, 1)
  111. [33554430] (3, 3, 8) (8, 3, 3)
  112. [33554416] (6, 5, 3)
  113. [30593745] (6, 7, 7) (7, 7, 6)
  114. [23194290] (7, 3, 6)
  115. [22282155] (1, 3, 2) (2, 3, 1)
  116. [19473111] (1, 1, 4) (4, 1, 1)
  117. [19168695] (1, 1, 8) (8, 1, 1)
  118. [17284575] (5, 7, 8) (8, 7, 5)
  119. [16777215] (1, 3, 3) (3, 3, 1) (5, 3, 9) (9, 3, 5)
  120. [16777208] (3, 5, 6)
  121. [16129169] (5, 1, 7) (7, 1, 5)
  122. [14351946] (3, 7, 7)
  123. [11597145] (6, 3, 7)
  124. [11184810] (2, 7, 5) (5, 7, 2)
  125. [11180715] (3, 7, 4) (4, 7, 3)
  126. [9266985] (3, 3, 7) (7, 3, 3)
  127. [8382465] (1, 1, 10)
  128. [8257473] (6, 9, 5)
  129. [7798308] (5, 5, 6)
  130. [7427385] (4, 9, 9)
  131. [7339976] (8, 1, 9) (9, 1, 8)
  132. [5963685] (4, 9, 5) (5, 9, 4)
  133. [5832615] (7, 1, 10)
  134. [5592405] (2, 1, 3) (3, 1, 2)
  135. [5374005] (5, 1, 9) (9, 1, 5)
  136. [5332341] (7, 3, 1)
  137. [5158440] (2, 1, 9)
  138. [4783982] (7, 7, 3)
  139. [3997791] (1, 9, 9)
  140. [2936010] (5, 1, 10)
  141. [2790571] (2, 9, 7) (7, 9, 2)
  142. [2579220] (9, 1, 2)
  143. [2162622] (3, 3, 5)
  144. [2149602] (2, 1, 7) (7, 1, 2)
  145. [1179612] (5, 5, 8) (8, 5, 5)
  146. [1081311] (5, 3, 3)
  147. [1048575] (1, 3, 9) (1, 5, 6) (6, 5, 1) (9, 3, 1)
  148. [1043970] (8, 5, 3)
  149. [1016379] (7, 9, 10)
  150. [1003935] (6, 1, 9) (9, 1, 6)
  151. [573405] (2, 7, 3) (3, 7, 2)
  152. [557039] (1, 1, 7) (7, 1, 1)
  153. [522753] (3, 3, 4) (4, 3, 3)
  154. [521985] (3, 5, 8)
  155. [458724] (7, 3, 8) (8, 3, 7)
  156. [390915] (4, 5, 7) (7, 5, 4)
  157. [278511] (6, 5, 5)
  158. [131070] (1, 4, 7) (1, 8, 9) (1, 10, 10) (2, 4, 9) (2, 5, 6) (2, 7, 4) (2, 7, 8) (2, 7, 10) (2, 8, 7) (4, 6, 7) (4, 7, 2) (4, 9, 4) (5, 2, 9) (5, 4, 7) (5, 6, 8) (5, 8, 7) (5, 8, 10) (6, 5, 2) (6, 8, 7) (7, 4, 1) (7, 4, 5) (7, 6, 4) (7, 8, 2) (7, 8, 5) (7, 8, 6) (8, 6, 5) (8, 7, 2) (8, 7, 10) (9, 2, 5) (9, 4, 2)
  159. [129794] (2, 5, 4) (2, 9, 8) (3, 5, 3) (4, 5, 2) (4, 5, 6) (5, 8, 9) (6, 5, 4) (8, 9, 2)
  160. [128961] (7, 5, 10)
  161. [126914] (6, 3, 10) (7, 6, 9) (7, 10, 9) (8, 6, 9) (9, 6, 7) (9, 6, 8)
  162. [114674] (1, 2, 7) (1, 2, 9) (3, 4, 10) (5, 10, 7) (7, 2, 1) (7, 2, 8) (7, 10, 5) (8, 2, 7) (9, 2, 1)
  163. [110670] (3, 2, 5) (5, 2, 3)
  164. [98301] (4, 7, 7) (7, 7, 4)
  165. [95046] (4, 4, 7) (5, 2, 2) (5, 6, 10) (7, 4, 4)
  166. [85974] (2, 4, 7) (6, 6, 1) (7, 4, 2)
  167. [65535] (2, 10, 4) (4, 10, 2) (5, 7, 10)
  168. [65534] (1, 3, 1) (1, 6, 5) (3, 4, 9) (3, 10, 5) (4, 7, 4) (5, 6, 1) (5, 6, 7) (5, 10, 3) (6, 3, 8) (7, 6, 5) (8, 3, 6) (9, 4, 3)
  169. [65532] (4, 10, 3)
  170. [65528] (1, 2, 3) (4, 5, 10) (7, 4, 9) (9, 4, 7)
  171. [64770] (1, 4, 9) (9, 4, 1)
  172. [63240] (3, 4, 4) (4, 4, 3) (8, 2, 9) (9, 2, 8)
  173. [61410] (2, 2, 7) (7, 2, 2)
  174. [61320] (9, 2, 10)
  175. [57316] (2, 3, 2) (6, 5, 8) (8, 5, 6)
  176. [57288] (3, 8, 7) (7, 8, 3)
  177. [55335] (4, 2, 6) (6, 2, 4) (8, 7, 9)
  178. [55118] (3, 8, 8) (8, 8, 3)
  179. [49146] (1, 8, 7) (2, 3, 8) (3, 4, 5) (5, 4, 3) (7, 8, 1) (8, 3, 2)
  180. [47523] (2, 2, 8) (8, 2, 2)
  181. [47244] (4, 7, 6) (6, 7, 4) (6, 10, 9)
  182. [43690] (1, 2, 5) (1, 10, 3) (3, 10, 1) (3, 10, 7) (5, 2, 1) (5, 4, 6) (6, 4, 5) (7, 2, 9) (7, 8, 8) (7, 10, 3) (8, 8, 7) (9, 2, 7) (9, 4, 10)
  183. [42966] (1, 8, 3) (2, 8, 5) (3, 8, 1) (3, 8, 5) (5, 8, 2) (5, 8, 3) (6, 7, 10)
  184. [40955] (3, 9, 8) (8, 9, 3)
  185. [39370] (5, 2, 6) (6, 2, 5)
  186. [32767] (2, 2, 6) (6, 2, 2)
  187. [32766] (2, 3, 6) (2, 9, 10) (2, 10, 9) (3, 2, 9) (3, 8, 6) (3, 10, 4) (3, 10, 10) (4, 4, 5) (4, 7, 10) (4, 9, 10) (5, 4, 4) (6, 3, 2) (6, 8, 3) (9, 2, 3)
  188. [32764] (3, 2, 1)
  189. [32752] (2, 6, 7) (4, 8, 5) (5, 8, 4) (7, 6, 2)
  190. [31682] (2, 2, 5)
  191. [31248] (6, 6, 5)
  192. [30660] (3, 7, 3)
  193. [28658] (1, 6, 6) (5, 4, 8) (8, 4, 5) (8, 10, 6)
  194. [28644] (3, 2, 10)
  195. [26670] (2, 10, 3) (3, 10, 2) (5, 10, 8) (8, 10, 5)
  196. [26214] (2, 2, 9) (2, 9, 4) (4, 9, 2) (9, 2, 2)
  197. [26040] (2, 8, 3)
  198. [24573] (2, 6, 10)
  199. [24528] (2, 5, 10) (5, 3, 5)
  200. [23622] (7, 6, 1)
  201. [22134] (3, 8, 4) (4, 8, 3)
  202. [21844] (3, 2, 4) (4, 2, 3)
  203. [21590] (3, 10, 9)
  204. [21483] (4, 6, 6) (6, 6, 4)
  205. [21420] (5, 2, 8) (8, 2, 5)
  206. [21336] (1, 10, 9)
  207. [20470] (7, 10, 10) (8, 10, 9)
  208. [20460] (7, 8, 9)
  209. [16383] (4, 6, 10) (4, 10, 10)
  210. [16002] (5, 10, 6) (6, 10, 5)
  211. [15810] (3, 5, 10)
  212. [15748] (1, 6, 7)
  213. [15624] (5, 6, 6)
  214. [15330] (1, 4, 10) (3, 10, 6) (4, 9, 6) (6, 9, 4) (6, 10, 3)
  215. [14329] (6, 10, 8)
  216. [14322] (2, 10, 10) (3, 6, 10) (4, 3, 6) (4, 6, 9) (6, 3, 4) (9, 6, 4) (9, 6, 10)
  217. [14280] (8, 6, 10)
  218. [13020] (3, 8, 2)
  219. [10922] (2, 4, 5) (5, 4, 2)
  220. [10710] (6, 6, 7) (7, 6, 6)
  221. [10668] (2, 10, 8)
  222. [10416] (4, 3, 4)
  223. [10230] (1, 5, 1)
  224. [9362] (1, 4, 6) (2, 3, 4) (3, 6, 7) (3, 10, 8) (4, 3, 2) (6, 4, 1) (6, 9, 8) (7, 6, 3) (8, 9, 6) (8, 10, 3)
  225. [9198] (3, 2, 6) (4, 10, 7) (6, 2, 3) (7, 10, 4)
  226. [9052] (2, 8, 9)
  227. [8190] (1, 6, 10) (1, 10, 6) (2, 6, 9) (4, 3, 10) (5, 4, 10) (5, 8, 6) (6, 4, 7) (6, 8, 5) (6, 10, 1) (6, 10, 7) (7, 2, 10) (7, 4, 6) (7, 10, 6) (9, 6, 2)
  228. [8184] (4, 2, 5) (5, 4, 9) (7, 6, 7) (9, 4, 5)
  229. [7905] (8, 6, 2)
  230. [7710] (2, 10, 7) (7, 10, 2)
  231. [7140] (6, 2, 9) (9, 2, 6)
  232. [7112] (5, 8, 1)
  233. [6510] (6, 10, 10)
  234. [5460] (3, 8, 10)
  235. [5334] (1, 10, 5) (5, 10, 1) (6, 8, 9)
  236. [5208] (3, 2, 7)
  237. [4774] (1, 2, 10)
  238. [4526] (4, 10, 6)
  239. [4284] (8, 3, 10)
  240. [4095] (6, 2, 10) (7, 2, 7)
  241. [4094] (2, 2, 10)
  242. [4092] (3, 2, 8) (5, 2, 4) (7, 10, 7) (8, 2, 3)
  243. [4088] (8, 8, 9)
  244. [3906] (4, 10, 9)
  245. [3810] (3, 6, 8) (8, 6, 3)
  246. [3556] (2, 5, 2) (9, 2, 9)
  247. [3472] (2, 6, 3) (3, 6, 2)
  248. [3276] (1, 4, 3) (3, 4, 1)
  249. [3069] (3, 10, 3) (5, 6, 5)
  250. [3066] (7, 8, 10)
  251. [2920] (2, 5, 8) (8, 5, 2)
  252. [2730] (1, 8, 10) (5, 2, 7) (6, 10, 2) (7, 2, 5) (7, 6, 10)
  253. [2570] (4, 8, 9)
  254. [2520] (4, 8, 7) (7, 8, 4)
  255. [2286] (1, 6, 9) (9, 6, 1)
  256. [2263] (6, 10, 4)
  257. [2142] (1, 10, 7) (2, 4, 3) (3, 4, 2) (7, 10, 1)
  258. [2114] (3, 4, 7) (7, 4, 3)
  259. [2044] (6, 5, 10)
  260. [1953] (3, 6, 3) (3, 9, 3) (6, 6, 8) (6, 9, 6) (8, 6, 6)
  261. [1778] (1, 8, 5)
  262. [1533] (3, 9, 9) (6, 6, 10) (9, 6, 3)
  263. [1530] (3, 4, 6) (5, 2, 10) (6, 4, 3)
  264. [1524] (2, 2, 3) (3, 2, 2) (7, 10, 8)
  265. [1365] (1, 10, 1) (2, 10, 6) (5, 2, 5)
  266. [1302] (3, 6, 5) (5, 6, 3) (7, 2, 3) (8, 2, 6)
  267. [1190] (2, 6, 4) (4, 6, 2)
  268. [1116] (5, 10, 9)
  269. [1068] (3, 4, 8) (8, 4, 3)
  270. [1023] (3, 3, 6) (6, 3, 3)
  271. [1022] (8, 2, 10)
  272. [1020] (4, 4, 9) (4, 10, 5) (5, 8, 8) (5, 10, 4) (6, 2, 7) (7, 2, 6) (8, 8, 5) (9, 4, 4)
  273. [1008] (1, 2, 6) (6, 2, 1)
  274. [930] (3, 6, 4) (4, 2, 7) (4, 6, 3) (7, 2, 4)
  275. [889] (8, 10, 2)
  276. [868] (1, 6, 2) (1, 10, 4) (2, 6, 1) (4, 2, 9) (4, 10, 1) (9, 2, 4)
  277. [840] (8, 6, 7)
  278. [762] (1, 4, 5) (5, 4, 1) (8, 10, 7)
  279. [682] (7, 4, 10)
  280. [630] (1, 6, 3) (2, 3, 10) (3, 6, 1) (5, 6, 9) (6, 4, 9) (9, 4, 6) (9, 6, 5)
  281. [511] (3, 6, 9)
  282. [510] (2, 6, 5) (2, 6, 8) (2, 8, 10) (2, 9, 6) (3, 8, 9) (4, 6, 5) (5, 6, 2) (5, 6, 4) (6, 9, 2)
  283. [508] (1, 2, 2) (1, 10, 8) (2, 2, 1) (4, 3, 8) (4, 9, 8) (6, 7, 8) (6, 9, 9) (8, 3, 4) (8, 7, 6) (8, 9, 4) (8, 10, 1) (9, 3, 9)
  284. [496] (1, 2, 8) (8, 2, 1)
  285. [476] (2, 7, 6) (6, 7, 2)
  286. [434] (6, 2, 8)
  287. [420] (7, 6, 8)
  288. [315] (8, 10, 10)
  289. [280] (8, 5, 10)
  290. [255] (4, 4, 8) (8, 4, 4)
  291. [254] (3, 8, 3) (4, 4, 10) (4, 6, 4) (4, 10, 8) (6, 8, 10) (8, 10, 4)
  292. [252] (1, 7, 1) (1, 10, 2) (2, 7, 2) (2, 10, 1) (4, 8, 10) (6, 4, 10) (7, 3, 7) (8, 8, 10) (8, 9, 10)
  293. [248] (4, 6, 8) (6, 6, 9) (9, 6, 6)
  294. [240] (1, 2, 4) (4, 2, 1)
  295. [234] (4, 5, 8) (8, 5, 4)
  296. [210] (1, 8, 6) (2, 6, 6) (6, 6, 2) (6, 8, 1)
  297. [186] (2, 8, 6) (2, 10, 2) (5, 4, 5) (6, 8, 2)
  298. [170] (3, 3, 9)
  299. [146] (3, 6, 6) (6, 6, 3)
  300. [127] (6, 9, 3)
  301. [126] (6, 4, 8) (7, 4, 7) (7, 4, 8) (8, 4, 6) (8, 4, 7)
  302. [124] (8, 6, 4)
  303. [120] (1, 4, 8) (1, 6, 4) (1, 6, 8) (4, 6, 1) (5, 7, 5) (5, 9, 5) (6, 5, 6) (6, 7, 6) (8, 4, 1) (8, 6, 1) (9, 6, 9)
  304. [105] (5, 10, 10)
  305. [102] (4, 8, 6) (6, 8, 4) (6, 8, 8) (6, 9, 10) (8, 8, 6)
  306. [93] (1, 6, 1) (3, 2, 3) (6, 3, 6)
  307. [85] (4, 2, 10) (9, 3, 3)
  308. [84] (2, 4, 6) (2, 6, 2) (2, 10, 5) (3, 4, 3) (5, 10, 2) (6, 4, 2) (8, 4, 10)
  309. [63] (6, 4, 6)
  310. [60] (2, 4, 4) (2, 4, 8) (4, 4, 2) (4, 10, 4) (5, 8, 5) (8, 4, 2)
  311. [56] (1, 4, 4) (4, 4, 1)
  312. [51] (6, 3, 9) (9, 3, 6)
  313. [48] (4, 4, 6) (4, 7, 8) (6, 4, 4) (8, 7, 4)
  314. [42] (2, 4, 10) (5, 5, 10)
  315. [35] (5, 5, 5)
  316. [32] (1, 1, 1) (1, 4, 2) (1, 8, 2) (1, 8, 4) (1, 9, 1) (2, 1, 2) (2, 1, 4) (2, 1, 6) (2, 1, 8) (2, 1, 10) (2, 4, 1) (2, 8, 1) (2, 9, 2) (3, 1, 3) (4, 1, 2) (4, 1, 4) (4, 1, 6) (4, 1, 8) (4, 1, 10) (4, 5, 4) (4, 8, 1) (5, 1, 5) (6, 1, 2) (6, 1, 4) (6, 1, 6) (6, 1, 8) (6, 1, 10) (7, 1, 7) (7, 5, 7) (7, 9, 7) (8, 1, 2) (8, 1, 4) (8, 1, 6) (8, 1, 8) (8, 1, 10) (8, 3, 8) (8, 4, 9) (8, 5, 8) (9, 1, 9) (9, 4, 8) (9, 5, 9)
  317. [31] (1, 2, 1) (3, 3, 3) (7, 7, 7)
  318. [30] (6, 8, 6)
  319. [24] (2, 8, 8)
  320. [21] (2, 2, 4) (4, 2, 2)
  321. [16] (1, 4, 1) (1, 8, 1) (1, 8, 8) (2, 2, 2) (4, 2, 8) (6, 2, 6) (6, 10, 6) (8, 2, 4) (8, 2, 8) (8, 8, 1) (9, 4, 9)
  322. [15] (2, 4, 2)
  323. [14] (6, 6, 6)
  324. [12] (4, 8, 8) (8, 8, 2) (8, 8, 4)
  325. [8] (2, 8, 2) (2, 8, 4) (4, 2, 4) (4, 4, 4) (4, 8, 2) (7, 8, 7) (8, 4, 8) (8, 6, 8) (8, 9, 8) (8, 10, 8)
  326. [7] (4, 8, 4) (5, 10, 5)
  327. [5] (3, 9, 6)
  328. [4] (8, 7, 8)
  329. [2] (8, 8, 8)
    ......5min timeout

可以看到,排在第一的恰巧是(1,3,10)周期为4294967295,正好是 232 - 1

一排多组,表示周期相等。

问题,为什么要有两次左移和一次右移呢?其实只一次左移加异或就能达到随机的效果。

猜测,之所以这样,大概是因为,第一次左移,是为了让高位多1,右移,是为了让低位多1,这样,高位低位都参与进来,增加随机性,第二次左移,便是真正的随机了。

行文至此结束。

尊重他人的劳动,转载请注明出处:http://www.cnblogs.com/aniao/p/aniao_exchanger.html

【JUC源码解析】Exchanger的更多相关文章

  1. 【JUC源码解析】ScheduledThreadPoolExecutor

    简介 它是一个线程池执行器(ThreadPoolExecutor),在给定的延迟(delay)后执行.在多线程或者对灵活性有要求的环境下,要优于java.util.Timer. 提交的任务在执行之前支 ...

  2. 【JUC源码解析】SynchronousQueue

    简介 SynchronousQueue是一种特殊的阻塞队列,该队列没有容量. [存数据线程]到达队列后,若发现没有[取数据线程]在此等待,则[存数据线程]便入队等待,直到有[取数据线程]来取数据,并释 ...

  3. 【JUC源码解析】ForkJoinPool

    简介 ForkJoin 框架,另一种风格的线程池(相比于ThreadPoolExecutor),采用分治算法,工作密取策略,极大地提高了并行性.对于那种大任务分割小任务的场景(分治)尤其有用. 框架图 ...

  4. 【JUC源码解析】DelayQueue

    简介 基于优先级队列,以过期时间作为排序的基准,剩余时间最少的元素排在队首.只有过期的元素才能出队,在此之前,线程等待. 源码解析 属性 private final transient Reentra ...

  5. 【JUC源码解析】CyclicBarrier

    简介 CyclicBarrier,一个同步器,允许多个线程相互等待,直到达到一个公共屏障点. 概述 CyclicBarrier支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后 ...

  6. 【JUC源码解析】ConcurrentLinkedQueue

    简介 ConcurrentLinkedQueue是一个基于链表结点的无界线程安全队列. 概述 队列顺序,为FIFO(first-in-first-out):队首元素,是当前排队时间最长的:队尾元素,当 ...

  7. Jdk1.6 JUC源码解析(12)-ArrayBlockingQueue

    功能简介: ArrayBlockingQueue是一种基于数组实现的有界的阻塞队列.队列中的元素遵循先入先出(FIFO)的规则.新元素插入到队列的尾部,从队列头部取出元素. 和普通队列有所不同,该队列 ...

  8. Jdk1.6 JUC源码解析(13)-LinkedBlockingQueue

    功能简介: LinkedBlockingQueue是一种基于单向链表实现的有界的(可选的,不指定默认int最大值)阻塞队列.队列中的元素遵循先入先出 (FIFO)的规则.新元素插入到队列的尾部,从队列 ...

  9. Jdk1.6 JUC源码解析(6)-locks-AbstractQueuedSynchronizer

    功能简介: AbstractQueuedSynchronizer(以下简称AQS)是Java并发包提供的一个同步基础机制,是并发包中实现Lock和其他同步机制(如:Semaphore.CountDow ...

随机推荐

  1. GCD学习(五) dispatch_barrier_async

    先看段代码 dispatch_queue_t concurrentQueue = dispatch_queue_create("my.concurrent.queue", DISP ...

  2. 汇编试验十五:安装新的int 9中断例程

    安装新的int 9中断例程(按'A'键后显示满屏幕的'A') int 9 是外中断,同样,程序编写还是和其他中断例程类似,安装(复制),调用: 不同点是在于,他要从端口读取数据60h, Source ...

  3. 如何设置活动监视器中的可见作业数能显示更长范围之内的作业(如何让bpdbjobs/Active Monitor显示更多作业信息)

    一.问题:     如何设置可以使得活动监视器中的可见作业数能显示更长范围之内的作业(即NBU软件不要自动删除活动监视器中短时间内(如8天)内的作业记录)? 二.解决方法:      默认情况下在Ac ...

  4. 用python实现ping

    #!/usr/bin/env python #coding=utf-8 import os import argparse import socket import struct import sel ...

  5. 十二、IntelliJ IDEA 中的版本控制介绍(中)

    由于 IntelliJ IDEA 支持的版本控制工具非常的多,但咱们真正能够用到的也就两三个而已,因此在本篇博文中,咱们主要介绍 SVN.Git 和 GitHub 的配置方法. SVN 如果想要在 I ...

  6. Mysql数据库的简单语法

    Mysql数据库是目前使用最为广泛的数据对,对于小型企业的支持度,比oracle数据库友好很多. mysql数据库的基本语法 1:创建并且使用数据库 找出服务器上当前存在什么数据库: SHOW DAT ...

  7. Xcode 7.0 SDK(Software Development Kit) 及 Sandbox(沙盒) 存放路径

    1. Sandbox(沙盒) 存放路径 我的硬盘/Users/wj121/Library/Developer/CoreSimulator/Devices/879D7E35-BE50-4620-97E1 ...

  8. Vue教程:Class 与 Style 绑定(四)

    绑定 HTML Class 对象语法 ①.添加单个class: <div v-bind:class="{ active: isActive }"></div> ...

  9. C语言输入输出函数总结

    常见函数: FILE *p char ch char buf[max] fopen("filename","ab")//打开名为filename的文件并返回一个 ...

  10. 商业化IM 客户端接口设计分析

    对于刚接触IM(即时通讯)开发,通过阅读成熟的商业代码能够对即时通讯软件大体上有个认识,比如消息发送,消息接受,消息监听,群聊,单聊,聊天室.我这边直接拿[Gobelieve IM]源码来做剖析.IM ...