我有一个用于crc32计算的以下util类:
import java.util.zip.CRC32;
import java.util.zip.Checksum;
public class StringUtils {
public static long crc32(String input) {
byte[] bytes = input.getBytes();
Checksum checksum = new CRC32();
checksum.update(bytes, 0, bytes.length);
return checksum.getValue();
}
}
对我来说,表现是一个非常重要的标准。
现在我正在考虑对这种方法进行可能的重构,并且我正在考虑将checksum
作为静态字段移动到类级别......这样的事情:
public class StringUtils {
public static Checksum checksum = new CRC32();
public static long crc32(String input) {
byte[] bytes = input.getBytes();
checksum.update(bytes, 0, bytes.length);
return checksum.getValue();
}
}
但我不确定它是否会在并发多线程环境中正常工作。请指教 - 这种重构是不是一个好主意。
答案 0 :(得分:4)
不,您的代码不是线程安全的。幸运的是,你可以通过一个简单的类使它成为线程安全的,几乎没有任何性能损失:
ThreadLocal<Checksum>
是你的答案。
答案 1 :(得分:3)
显然你不能在多线程环境中这样做,因为CRC32
类不是线程安全的。
简短回答:它不是线程安全的,因为它的javadoc不包含这个提示。
更详细:如果你打开CRC32
类的源代码,你会看到,这个类没有包含任何同步块,它不是原子的,并且包含对象变量
private int crc;
未同步。
UPD:但您可以将ThreadLocal<Checksum>
用作@Dariusz suggested in his answer。
答案 2 :(得分:1)
正如其他人所说,CRC32不是线程安全的,因此您必须同步或使用ThreadLocal,但这些并不是特别有帮助。
如果你看一下CRC32的实现,那就是一个字段。在您执行任何操作之前,请对您的代码进在Java复杂的GC,JIT和逃逸分析之间,很难预测你是否会看到任何好处。
重写这个以避免数组分配可能会带来更大的好处:
byte[] bytes = input.getBytes();
编辑:请不要这样做,除非你绝对必须这样做。
这将展开String的内部getBytes()
以避免一些中间缓冲,并利用CRC32对直接字节缓冲区进行优化:
public class StringUtils {
private static final ThreadLocal<ByteBuffer> BUFFER = ThreadLocal.withInitial(() -> ByteBuffer.allocateDirect(4094));
public static long crc32(String input) {
CharBuffer inputBuffer = CharBuffer.wrap(input);
ByteBuffer buffer = BUFFER.get();
CRC32 crc32 = new CRC32();
CharsetEncoder encoder = Charset.defaultCharset().newEncoder();
CoderResult coderResult;
do {
try {
coderResult = encoder.encode(inputBuffer, buffer, true);
buffer.flip();
crc32.update(buffer);
} finally {
buffer.reset();
}
} while (coderResult.isOverflow());
return crc32.getValue();
}
}
您可以通过手动执行编码(对于ASCII非常简单)来做得更好。使性能复杂化的是平衡将字节复制到缓冲区中以便通过对实际CRC32实现的JNI调用来读取它们。由于JNI开销,中间缓冲区实际上可能更快。在执行此操作之前,请务必阅读direct bytebuffers;如果你实际上没有重复使用缓冲区,这可能会很慢。
当你真正深入了解正在发生的事情时,你会发现getBytes()
比你意识到的要复杂得多,并且担心分配一个简单的,短命的CRC32对象不是表现的主要贡献者。