高洛峰2017-04-18 10:25:09
System.arraycopy
は ネイティブ
メソッドです: System.arraycopy
是一个 native
方法:
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
而 native
方法和线程安全之间又没有什么必然联系, 并且我看 System.arraycopy
的文档中也没有提到它是线程安全的, 因此就可以知道它是 线程不安全的
.
不过为了验证 System.arraycopy
是否真的是线程不安全的, 我写了一个小例子:
public class ArrayCopyThreadSafe {
private static int[] arrayOriginal = new int[1024 * 1024 * 10];
private static int[] arraySrc = new int[1024 * 1024 * 10];
private static int[] arrayDist = new int[1024 * 1024 * 10];
private static ReentrantLock lock = new ReentrantLock();
private static void modify() {
for (int i = 0; i < arraySrc.length; i++) {
arraySrc[i] = i + 1;
}
}
private static void copy() {
System.arraycopy(arraySrc, 0, arrayDist, 0, arraySrc.length);
}
private static void init() {
for (int i = 0; i < arraySrc.length; i++) {
arrayOriginal[i] = i;
arraySrc[i] = i;
arrayDist[i] = 0;
}
}
private static void doThreadSafeCheck() throws Exception {
for (int i = 0; i < 100; i++) {
System.out.println("run count: " + (i + 1));
init();
Condition condition = lock.newCondition();
new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
condition.signalAll();
lock.unlock();
copy();
}
}).start();
lock.lock();
// 这里使用 Condition 来保证拷贝线程先已经运行了.
condition.await();
lock.unlock();
Thread.sleep(2); // 休眠2毫秒, 确保拷贝操作已经执行了, 才执行修改操作.
modify();
if (!Arrays.equals(arrayOriginal, arrayDist)) {
throw new RuntimeException("System.arraycopy is not thread safe");
}
}
}
public static void main(String[] args) throws Exception {
doThreadSafeCheck();
}
}
这个例子的具体操作是:
arrayOriginal 和 arraySrc 初始化时是相同的, 而 arrayDist 是全为零的.
启动一个线程运行 copy()
方法来拷贝 arraySrc 到 arrayDist 中.
在主线程执行 modify()
操作, 修改 arraySrc 的内容. 为了确保 copy()
操作先于 modify()
操作, 我使用 Condition, 并且延时了两毫秒, 以此来保证执行拷贝操作(即System.arraycopy) 先于修改操作.
根据第三点, 如果 System.arraycopy
是线程安全的, 那么先执行拷贝操作, 再执行修改操作时, 不会影响复制结果, 因此 arrayOriginal 必然等于 arrayDist; 而如果 System.arraycopy
是线程不安全的
リーリー
native
メソッドとスレッド セーフの間には必要な関係はありません。また、System.arraycopy
のドキュメントにはスレッド セーフであるとは記載されていないことがわかりました。 スレッド安全でない
ことがわかります。System.arraycopy
が本当にスレッドアンセーフかどうかを検証するために、小さな例を書きました: この例の具体的な操作は次のとおりです:
<オル>arrayOriginal と arraySrc は初期化時には同じですが、arrayDist はすべてゼロです。
🎜copy()
メソッドを実行して arraySrc を arrayDist にコピーするスレッドを開始します。🎜🎜
modify()
オペレーションをメインスレッドで実行して、arraySrc の内容を変更します。これは、copy()
オペレーションが modify よりも前に行われるようにするためです。 ()
操作には、Condition を使用し、変更操作の前にコピー操作 (つまり、System.arraycopy) が確実に実行されるように、2 ミリ秒遅らせます。🎜🎜
System.arraycopy
がスレッドセーフである場合、最初にコピー操作を実行してから変更操作を実行してもコピー結果には影響しないため、arrayOriginal は等しい必要がありますSystem.arraycopy
が thread-unsafe
の場合、arrayOriginal は arrayDist.🎜🎜 と等しくありません。
🎜
🎜
🎜上記の推論に基づいて、プログラムを実行すると、次の出力が得られます:🎜
リーリー
🎜最初の 2 回はうまくいきましたが、3 回目はうまくいかなかったことがわかります。🎜