Adakah nisbah bebas kunci dan terkunci dalam kod berikut merupakan pelaksanaan yang lebih baik? Saya menggunakan jmeter untuk membuat 20 permintaan sesaat Kebanyakan output operasi tidur dalam pelaksanaan kod bebas kunci test()
sangat berbeza daripada 500 milisaat, manakala output kod terkunci pada asasnya ialah 500 milisaat dengan perbezaan 1 atau. 2 milisaat masalah ini sangat pelik
@Controller
@RequestMapping("/bench/")
public class BenchController {
@Autowired
private FlowService flowService;
private static Object[] lockObj;
private static AtomicReference<Integer>[] locks;
static {
lockObj = new Object[100];
for (int i = 0; i < lockObj.length; i++) {
lockObj[i] = new Object();
}
locks = new AtomicReference[100];
for (int i = 0; i < locks.length; i++) {
locks[i] = new AtomicReference<Integer>(null);
}
}
@RequestMapping("a")
@ResponseBody
public long a(int id) throws Exception {
long start = System.currentTimeMillis();
int index = id % 100;
long inner=0;
synchronized (lockObj[index]) {
inner=test();
}
long result = System.currentTimeMillis() - start;
System.out.println("all: "+result+" inner: "+inner);
return result;
}
@RequestMapping("b")
@ResponseBody
public long b(int id) throws Exception {
long start = System.currentTimeMillis();
AtomicReference<Integer> lock=locks[id % 100];
while (!lock.compareAndSet(null, id)) {}
long inner=test();
boolean flag=lock.compareAndSet(id, null);
long result = System.currentTimeMillis() - start;
System.out.println("all: "+result+" inner: "+inner+" flag:"+flag);
return result;
}
public long test()throws Exception{
long innerstart = System.currentTimeMillis();
Thread.sleep(500);
System.out.println(System.currentTimeMillis()-innerstart);
return System.currentTimeMillis()-innerstart;
}
}
1 Pertama sekali, mari kita jelaskan dua isu yang disegerakkan secara umumnya tidak dibandingkan dengan kelas AtomicXX, tetapi lebih banyak lagi dengan kelas ReentrantLock Terdapat banyak perbandingan antara kedua-duanya di Internet, anda boleh google sendiri.
2 Berkenaan soalan tiada kunci atau kunci, kod dalam kod ujian b bermasalah,
Untuk kaedah a, blok kod disegerakkan, selepas kunci dipegang oleh utas masuk pertama, utas berikutnya yang meminta untuk memperoleh kunci akan disekat dan digantung Sehingga utas sebelumnya melepaskan kunci, utas berikutnya akan meneruskan pelaksanaan kepada kewujudan kunci, 20 permintaan adalah serupa dengan pelaksanaan berurutan, lapisan ini dijadualkan oleh jvm
Untuk kaedah b, pengoperasian cas tidak menyekat Gelung while dalam kaedah sebenarnya sentiasa dilaksanakan (secara berterusan cuba melakukan operasi cas), dan kita tahu bahawa gelung tak terhingga akan menggunakan sumber CPU. Lebih banyak utas, lebih banyak operasi CAS di sini, yang pasti akan membawa kepada lonjakan dalam penggunaan CPU Apabila kod dalam kaedah B diuji oleh jmeter, secara teorinya perlu sentiasa ada 20 utas yang aktif CPU dan model utas adalah Topik lain , thread number tuning adalah topik yang agak advance dalam jvm Kalau berminat boleh google sendiri
Mari kita bincangkan tentang ReentrantLock dan disegerakkan: Biasanya dalam keadaan serentak yang tinggi, ReentrantLock mempunyai prestasi yang lebih baik daripada yang disegerakkan, dan ReentrantLock menyediakan beberapa fungsi yang tidak disediakan oleh penyegerakan (peninggalan masa kunci secara automatik, dsb.) boleh dikurangkan dalam kod sampel masa, dengan itu mensimulasikan jeda yang lebih pendek dan 500ms yang lebih tinggi adalah sangat singkat untuk manusia, tetapi pada asasnya ia adalah nombor astronomi untuk CPU contoh kod:
Kaedah c dilaksanakan menggunakan ReentrantLock Dalam kebanyakan kes, ReentrantLock lebih cekap daripada disegerakkan
juc (java.util.concurrent) ialah pakej serentak berasaskan baris gilir Secara lalai, utas akan diletakkan (menggantung operasi) apabila persaingan kunci (putaran) melebihi 1000 nanosaat untuk mengurangkan penukaran benang yang kerap CPU, anda boleh cuba melaraskan parameter masa tidur dalam kaedah c.
Kaedah ujian, jmeter tidak dipasang pada mesin ini, ujian dilakukan dengan apache ab, arahan ujian: