最近在学习pomelo的时候,偶然在网上看到博文《史上最强算法论战:请不要嘻哈,这是哈希》
http://chuansong.me/n/1489885
被作者的文笔吸引,对其中的干货很有兴趣,随后用一周时间进行了膜拜。现将学习结果总结如下。
- 1.所谓无锁设计,是不使用编程语言的多线程锁转而使用cpu的锁(总线锁,寄存器锁,缓存锁)
- 2.CAS原语有好多种写法,目前的物理服务器都是多cpu多核心,所以需要按Test and test and set 的写法编程。
- 3.当前的现代cpu,Cache Line 是64byte .机器的字长是64bit.cpu只对16,32,64 bit的数据提供原子操作。
未解决的问题:这货到底是用在什么业务场景的,一直没想明白,所以也没办法写出来测试程序。请iteye上的大师指点。
package testPatternBox;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.LockSupport;
class BackOffAtomicLong
{
private final AtomicLong value = new AtomicLong ( 0L );
public long get ( )
{
return value.get ( );
}
public long incrementAndGet ( )
{
for ( ;; )
{
long current = get ( );
long next = current + 1;
if ( compareAndSet ( current ,
next ) )
return next;
}
}
public long subtractAndGet ( )
{
for ( ;; )
{
long current = get ( );
long next = current - 1;
if ( compareAndSet ( current ,
next ) )
return next;
}
}
public boolean compareAndSet ( final long current ,
final long next )
{
if ( value.compareAndSet ( current ,
next ) )
{
return true;
}
else
{
LockSupport.parkNanos ( 1L );
return false;
}
}
public void set ( final long l )
{
value.set ( l );
}
}
class DataItem
{// 数据项
/**
* 而compoundKey为(股东代码,股票代码,持仓类型,flag)的复合体,股东代码占用最63~27位(5位字符和四个字节无符号整数),
* 股票代码占26~11位(两个字节),持仓类型占用10~6位(五个字节),isTail占用第5位,表示是否为尾部,
* 即后继元素中没有相同hash值的元素。 doWrite占用第4位,表示该key正在更改/写入,
* readerCount占用3~0为表示该key正在读的线程数量。
*/
/**
* 每条持仓记录,由三个信息来定位(key): 持仓类型(一位字符,A~F), 股东代码(10位字符,第1位A~Z,后面9位是数字0~9),
* 股票代号(short类型)
*
* 被定位到的持仓记录是一个64bit的值(value)
*/
private BackOffAtomicLong compoundKey = new BackOffAtomicLong ( ); // 数据项的关键字
private BackOffAtomicLong value = new BackOffAtomicLong ( );;// 存储的值
public DataItem ( Long key , Long value )
{
this.compoundKey.set ( key );
this.value.set ( value );
}
public Long getKey ( )
{
return compoundKey.get ( );
}
public BackOffAtomicLong getBackOffAtomicLongKey ( )
{
return compoundKey;
}
public boolean setKey ( Long key )
{
return this.compoundKey.compareAndSet ( this.compoundKey.get ( ) ,
key );
}
public Long getValue ( )
{
return value.get ( );
}
public BackOffAtomicLong getBackOffAtomicLongValue ( )
{
return value;
}
public boolean setValue ( Long value )
{
return this.value.compareAndSet ( this.value.get ( ) ,
value );
}
public boolean equals ( DataItem di )
{
if ( this.getKey ( ) == di.getKey ( ) && this.getValue ( ) == di.getValue ( ) )
return true;
else
return false;
}
}
class DataItemUtils
{// 用来处理DataItem元素 ,由于看不懂文章里的维护策略,暂时没有使用。
/**
* tail位为0时表示不是尾,为1时表示是尾
*
* @return 是否是最后一个元素
*/
public static boolean isTail ( DataItem i )
{
return ( ( i.getKey ( ) ) & ( 12L ) ) == 12L;
}
public static boolean setIsTail ( DataItem i )
{
return i.setKey ( i.getKey ( ) | 12L );
}
public static boolean setIsNotTail ( DataItem i )
{
return i.setKey ( i.getKey ( ) & 9223372036854775791L );
}
/**
* 0 未写入 1正在写入
*
* @param i
* @return
*/
public static boolean isWrite ( DataItem i )
{
return ( ( i.getKey ( ) ) & ( 8L ) ) == 8L;
}
public static boolean setIsWrite ( DataItem i )
{
return i.setKey ( i.getKey ( ) | 8L );
}
public static boolean setIsNotWrite ( DataItem i )
{
return i.setKey ( i.getKey ( ) & 9223372036854775799L );
}
/**
* 是否有线程在读
*/
public static boolean isReading ( DataItem i )
{
return ( ( i.getKey ( ) ) & ( 7L ) ) != 0L;
}
public boolean incrementReading ( DataItem i )
{
if ( ( ( i.getKey ( ) ) & ( 7L ) ) == 7L )
return true;
i.getBackOffAtomicLongKey ( ).incrementAndGet ( );
return true;
}
public boolean subtractReading ( DataItem i )
{
if ( ( ( i.getKey ( ) ) & ( 7L ) ) == 0L )
return true;
i.getBackOffAtomicLongKey ( ).subtractAndGet ( );
return true;
}
}
public class MemoryHashTable
{// 数组实现的哈希表,开放地址法之再哈希法
private DataItem[] hashArray; // 存数据的数组
private int arraySize;
private DataItem nonItem; // 已删除标志
private int contstant; // 二次hash函数因子。
MemoryHashTable ( int size )
{// 哈希表构造函数
arraySize = findPrimeNumber ( size );
hashArray = new DataItem[arraySize];
nonItem = new DataItem ( -1L , -1L );
contstant = findPrimeNumber ( arraySize / 10 );
}
public void displayTable ( )// 输出哈希表
{
System.out.print ( "Table: " );
for ( int j = 0 ; j < arraySize ; j++ )
{
if ( hashArray[j] != null )
System.out.print ( hashArray[j].getKey ( ) + " " );
else
System.out.print ( "** " );
}
System.out.println ( "" );
}
// 哈希函数1
private int hashFunc1 ( long key )
{
return Integer.parseInt ( Long.toString ( key % arraySize ) );
}
// 哈希函数2,不同于哈希函数1,用于再哈希。
private int hashFunc2 ( long key )
{
// array size must be relatively prime to 5, 4, 3, and 2
return Integer.parseInt ( Long.toString ( contstant - key % contstant ) );
}
// 哈希表中插入数据 这里的CAS是 Test and Test and Test and set
public void insert ( long key ,long value)
{
int hashVal = hashFunc1 ( key); // 求关键字的哈希值
int stepSize = hashFunc2 ( key ); // 再探测步长的大小
while ( hashArray[hashVal] != null && hashArray[hashVal].getKey ( ) != -1 )
{
if ( hashArray[hashVal].getKey ( ) == key)
{
//判断当前对象是我们要操作的对象
hashArray[hashVal].setValue ( value );
return ;
}
else
{
hashVal += stepSize; // 单元被占用,再探测
hashVal %= arraySize;
}
}
//此处存在线程不安全问题,如果两个线程中的hashkey完全相同,同时写这个hashVal位置会怎么样???
hashArray[hashVal] = new DataItem ( key , value );
}
// 在哈希表中删除
public DataItem delete ( long key )
{
int hashVal = hashFunc1 ( key );
int stepSize = hashFunc2 ( key );
while ( hashArray[hashVal] != null )
{// 直到一个空单元出现
if ( hashArray[hashVal].getKey ( ) == key )
{
DataItem temp = hashArray[hashVal];
hashArray[hashVal] = nonItem; // 作删除标记
return temp;
}
hashVal += stepSize; // 再探测
hashVal %= arraySize;
}
return null;
}
// 在哈希表中搜索
public long find ( long key )
{
int hashVal = hashFunc1 ( key );
int stepSize = hashFunc2 ( key );
while ( hashArray[hashVal] != null )
{
if ( hashArray[hashVal].getKey ( ) == key )
return hashArray[hashVal].getValue ( );
hashVal += stepSize;
hashVal %= arraySize;
}
return 0L;
}
/**
* 找出大于capacity 的最小质数,并且该质数容量是minseed的7分之10 hashtable的装载率不能大于70%
* 用开放地址探测的散列,要保证在一定步数内找到一个空位, 你必须让数组长度为一个质数。在装载率为70%的情况下,
* 一个质数长度的数组,基本就是几步之内你就一定能找到一个空位。
*
* @param capacity
* hashtable的容量。
*
* @return
*/
private Integer findPrimeNumber ( int capacity )
{
capacity = capacity * 10 / 7; // 预计装载量是hashtable容量的70%
if ( capacity % 2 == 0 )
{
// 质数肯定是奇数
capacity++ ;
}
if ( capacity <= 1 )
{
return 2;
}
if ( capacity == 2 || capacity == 3 )
{
return 5;
}
while ( true )
{
int sqrt = (int) Math.sqrt ( capacity );
for ( int i = 3 ; i <= sqrt ; i += 2 )
{
if ( capacity % i == 0 )
{
capacity += 2;
break;
}
}
return capacity;
}
}
}
分享到:
相关推荐
哈希算法的关键特性是,对于任何两个不同的输入,其输出的哈希值应当是唯一的,尽管这在理论上不可能完全实现,但在实际应用中,冲突(两个不同的输入得到相同的哈希值)是不可避免的。 1. 哈希算法概念: 哈希...
Java实现哈希算法-哈希函数的高效实现、排序算法数据结构 在 Java 中实现哈希算法是非常重要的,因为哈希函数的速度和安全性对整个系统的性能和安全性产生了巨大的影响。在本文中,我们将讨论如何在 Java 中实现...
综上所述,这个项目通过提供封装好的Java接口,展示了如何在实际开发中获取数据的哈希值以及识别所使用的哈希算法,这对于理解和应用Java中的哈希计算至关重要。对于初学者或者需要这方面功能的开发者来说,这是一个...
5. sphlib库的使用:sphlib库是一个开源的实现,提供了许多加密哈希函数的实现,实际上,Java版本比Sun/Oracle提供的标准JRE更快。 6. 性能测量数据:需要对哈希函数的性能进行实际测量,例如对L1缓存的影响可能会...
**感知哈希算法详解与Matlab实现** 感知哈希(Perceptual Hashing,简称pHash)是一种图像识别技术,用于判断两张图片是否相似。它通过模拟人类视觉系统的感知特性,将图片转换成一个简短的哈希值,进而进行比较。...
在《数据结构与算法分析:Java语言描述》一书中,作者深入探讨了这一领域的关键概念和技术,并通过Java编程语言进行了具体的实现和演示。 ### 数据结构 数据结构是指在计算机中存储、组织数据的方式,它不仅影响到...
在上述代码中,`GetHashTablePos` 函数实现了基于暴雪哈希算法的哈希表查找过程,其中包含以下步骤: 1. 计算字符串的哈希值。 2. 计算哈希地址。 3. 如果哈希地址处已有数据,检查是否为所需字符串。 4. 如果不是,...
本文主要关注的是如何在8位单片机上实现SHA1哈希算法,这是一种广泛使用的哈希算法,能够确保数据的完整性。 SHA1(Secure Hash Algorithm 1)是由美国国家安全局(NSA)设计的,它产生一个160位(20字节)的哈希值...
总的来说,Java国密算法实现涉及了椭圆曲线加密和哈希函数两大核心概念,通过合理运用这些算法,可以构建安全可靠的加密通信和数据保护系统。在具体编程时,需要对算法原理有深入理解,并熟练掌握相关库的使用,以...
在这个数据结构作业中,我们将深入探讨哈希算法的原理、实现方式以及其在实际问题中的应用。 首先,理解哈希算法的基本特性至关重要。理想的哈希函数应该满足以下几个条件: 1. **确定性**:对于相同的输入,哈希...
一致性哈希算法是一种在分布式系统中解决数据分片和负载均衡问题的算法,它主要解决了在动态添加或移除节点时,尽可能少地改变已经存在的数据分布。在云计算和大数据处理领域,一致性哈希被广泛应用,例如在分布式...
在实际编程中,你可以使用.NET Framework提供的System.Security.Cryptography命名空间中的类来实现这两种哈希算法。例如,对于MD5,你可以使用MD5类的ComputeHash方法;对于SHA256,你可以使用SHA256类。这些类提供...
在本压缩包中,你可能会找到多种常见的哈希算法的代码实现,如MD5(Message-Digest Algorithm 5)、SHA-1(Secure Hash Algorithm 1)、SHA-256以及SHA-3等。这些算法都具有将任意长度的信息映射为固定长度输出的...
哈希计算工具 `java-hash` 是一款基于Java编程语言实现的专门用于进行哈希值计算的软件。在软件开发和信息安全领域,哈希算法扮演着至关重要的角色,它能够将任意长度的数据转换为固定长度的输出,这个输出被称为...
在这个项目中,我们使用Java来实现Apriori算法。首先,我们需要处理数据,这通常意味着从Excel文件中读取数据。Java提供了多种方式来操作Excel文件,如Apache POI库。POI库允许开发者读取、写入和修改Microsoft ...
本文将深入探讨如何利用Python编程语言和哈希算法来有效地实现图像去重。 首先,我们要理解哈希算法的基本原理。哈希(Hash)算法是一种将任意长度的输入(也叫做预映射)通过一个算法,变换成固定长度的输出,这个...
综上所述,Java中的国密算法实现涉及多个步骤和技术,包括但不限于密钥管理、加密解密、哈希计算、签名验证以及证书处理。开发者需要熟悉相关API和库,以正确地集成这些功能到他们的项目中。在实际开发过程中,还要...
在Java中,可以使用`java.security.MessageDigest`类来实现MD5哈希: ```java import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MD5Example { public ...
### 暴雪哈希算法源码解析与应用 #### 一、暴雪哈希算法...对于想要深入了解哈希算法原理及其实现的新手而言,暴雪哈希算法不仅具有很高的学习价值,还能够帮助开发者理解如何在实际项目中应用哈希算法解决具体问题。
一致性哈希算法是一种分布式哈希(Distributed Hash Table, DHT)技术,它解决了在分布式环境中数据分片和负载均衡的问题。在传统的哈希算法中,如果增加或减少服务器节点,会导致大量数据重新分配,而一致性哈希...