きっかけ
「synchronizedは遅い」って、本当なのかな?
だからと言って構文を崩して歪みを作り込むことが正しいのだろうか?
ていうか、synchronizedの何が遅いのかな
試したこと
int i = 0;
int len = 0x3fffff;
int n1 = 0;
long g1 = 0L;
long g2 = 0L;
long g3 = 0L;
Object signal = new Object();
//pattern1
//ここが基準
g1 = System.nanoTime();
for(i=0;len > i;i++){
n1++;
}
g2 = System.nanoTime();
g3 = g2 - g1;
System.out.println("pattern1: "+g3);
//pattern2
//同期ブロック実装の基本形
n1 = 0;
g1 = System.nanoTime();
synchronized(signal){
for(i=0;len > i;i++){
n1++;
}
}
g2 = System.nanoTime();
g3 = g2 - g1;
System.out.println("pattern2: "+g3);
//pattern3
//あえてループの中
n1 = 0;
g1 = System.nanoTime();
for(i=0;len > i;i++){
synchronized(signal){
n1++;
}
}
g2 = System.nanoTime();
g3 = g2 - g1;
System.out.println("pattern3: "+g3);
//pattern4
//すでにmonitor取得してたらどうなるかな?
n1 = 0;
g1 = System.nanoTime();
synchronized(signal){
for(i=0;len > i;i++){
synchronized(signal){
n1++;
}
}
}
g2 = System.nanoTime();
g3 = g2 - g1;
System.out.println("pattern4: "+g3);
return;
結果
pattern1: 20251625
pattern2: 19778709
pattern3: 57471125
pattern4: 153819000
わかったこと
- synchronizedに入る
- synchronizedから出る
のどちらか?もしくは両方?が高コストと言うことですね(2と3の比較)
synchronizedに入るタイミングで行うクラスインスタンスのmonitorを取得する部分が遅いんだろうなあ
だって、他のスレッドと歩調とらないといけない
あーでも、monitorを手放すタイミングで待ってる他のスレッドのスケジューリングするわけだから、これもコスト高そう
ていうか、プログラムのプロセス内だけの排他制御なので「まだこれで済んでる」とも言える
synchronizedブロックの中は、実行速度に影響はなさそうです(1と2の比較)
monitor取得の再入が、高コストだった(3と4の比較)
てっきり再入はコスト低いものだと思ってました
対処
JAVA創成期から言われてたこと、そのままです
「無駄なsynchronizedブロックに入る回数を減らす検討をしましょう」