konkurensi bebas kunci java
我想大声告诉你
我想大声告诉你 2017-05-17 10:01:02
0
1
662

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;
    }
}
我想大声告诉你
我想大声告诉你

membalas semua(1)
曾经蜡笔没有小新

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:

package com.gzs.learn.springboot;

import java.util.LinkedList;
import java.util.Random;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/bench/")
public class BenchController {
    private Random random = new Random();
    private static Object[] lockObj;
    private static AtomicReference<Integer>[] locks;
    private static ReentrantLock[] reentrantLocks;
    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);
        }
        reentrantLocks = new ReentrantLock[100];
        for (int i = 0; i < reentrantLocks.length; i++) {
            reentrantLocks[i] = new ReentrantLock();
        }
    }

    @RequestMapping("a/{id}")
    @ResponseBody
    public long a(@PathVariable("id") 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/{id}")
    @ResponseBody
    public long b(@PathVariable("id") int id) throws Exception {
        long start = System.currentTimeMillis();
        id = id % 100;
        AtomicReference<Integer> lock = locks[id];
        int b = 0;
        while (!lock.compareAndSet(null, id)) {
            b = 1 + 1;
        }
        long inner = test();
        boolean flag = lock.compareAndSet(id, null);
        long result = System.currentTimeMillis() - start;
        System.out.println("all: " + result + " inner: " + inner + " flag:" + flag);
        System.out.println(b);
        return result;
    }

    @RequestMapping("c/{id}")
    @ResponseBody
    public long c(@PathVariable("id") int id) throws Exception {
        long start = System.currentTimeMillis();
        id = id % 100;
        ReentrantLock lock = reentrantLocks[id];
        lock.lock();
        long inner = test();
        lock.unlock();
        long result = System.currentTimeMillis() - start;
        System.out.println("all: " + result + " inner: " + inner);
        return result;
    }

    public long test() throws Exception {
        long innerstart = System.currentTimeMillis();
        Thread.sleep(0, 100);
        // Thread.sleep(500);
        System.out.println(System.currentTimeMillis() - innerstart);
        return System.currentTimeMillis() - innerstart;
    }
}
  • Kaedah c dilaksanakan menggunakan ReentrantLock Dalam kebanyakan kes, ReentrantLock lebih cekap daripada disegerakkan

  • Kelas teras Aqs (AbstractQueuedSynchronizer) dalam
  • 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:

ab -n 100 -c 20  http://localhost:8080/bench/a/10
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!