Rumah >Java >javaTutorial >Cara menggunakan Lock dalam Java multithreading

Cara menggunakan Lock dalam Java multithreading

PHPz
PHPzke hadapan
2023-05-12 14:46:061556semak imbas

Selepas Jdk1.5, di bawah pakej java.util.concurrent.locks, terdapat satu set antara muka dan kelas yang melaksanakan penyegerakan benang Apabila ia berkaitan dengan penyegerakan benang, semua orang mungkin memikirkan kata kunci yang disegerakkan,

Ini ialah kata kunci terbina dalam Java, digunakan untuk mengendalikan penyegerakan benang Walau bagaimanapun, kata kunci ini mempunyai banyak kelemahan dan tidak begitu mudah dan intuitif untuk digunakan, jadi Kunci muncul di bawah, kami

akan membandingkan Mari jelaskan Kunci.

Biasanya kita menghadapi masalah berikut apabila menggunakan kata kunci yang disegerakkan:

(1) Tidak dapat dikawal, tidak dapat mengunci dan melepaskan kunci sesuka hati.

(2) Kecekapan agak rendah Contohnya, kami sedang membaca dua fail serentak. Bacaan dan bacaan tidak mempunyai pengaruh antara satu sama lain ,

Jadi selagi satu thread masuk, thread lain kena tunggu.

(3) Tidak ada cara untuk mengetahui sama ada benang telah memperoleh kunci.

Kunci boleh menyelesaikan masalah yang disegerakkan di atas dengan baik, dan selepas jdk1.5, pelbagai kunci juga disediakan, seperti kunci baca-tulis, tetapi ada satu perkara yang perlu diperhatikan, gunakan segerak

Apabila keadaan kritikal, anda tidak perlu melepaskan kunci secara manual, tetapi anda mesti melepaskan kunci secara manual apabila menggunakan Kunci. Mari belajar tentang kunci Kunci.

Kunci ialah antara muka lapisan atas Prototaipnya adalah seperti berikut, menyediakan sejumlah 6 kaedah:

public interface Lock {
  // 用来获取锁,如果锁已经被其他线程获取,则一直等待,直到获取到锁
   void lock();
  // 该方法获取锁时,可以响应中断,比如现在有两个线程,一个已经获取到了锁,另一个线程调用这个方法正在等待锁,但是此刻又不想让这个线程一直在这死等,可以通过
    调用线程的Thread.interrupted()方法,来中断线程的等待过程
  void lockInterruptibly() throws InterruptedException;
  // tryLock方法会返回bool值,该方法会尝试着获取锁,如果获取到锁,就返回true,如果没有获取到锁,就返回false,但是该方法会立刻返回,而不会一直等待
   boolean tryLock();
  // 这个方法和上面的tryLock差不多是一样的,只是会尝试指定的时间,如果在指定的时间内拿到了锁,则会返回true,如果在指定的时间内没有拿到锁,则会返回false
   boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
  // 释放锁
   void unlock();
  // 实现线程通信,相当于wait和notify,后面会单独讲解
   Condition newCondition();
}

Jadi bagaimana untuk menggunakan kaedah ini? Seperti yang kami nyatakan sebelum ini, menggunakan Kunci memerlukan pelepasan kunci secara manual Walau bagaimanapun, jika pengecualian dilemparkan dalam program, kunci tidak boleh dilepaskan, yang boleh menyebabkan kebuntuan

Jadi apabila kita menggunakan Lock , mempunyai a format tetap, seperti berikut:

Lock l = ...;
      l.lock();
      try {
        // access the resource protected by this lock
      } finally {// 必须使用try,最后在finally里面释放锁
        l.unlock();
      }

Mari kita lihat contoh mudah, kodnya adalah seperti berikut:

/**
 * 描述:Lock使用
 */
public class LockDemo {
    // new一个锁对象,注意此处必须声明成类对象,保持只有一把锁,ReentrantLock是Lock的唯一实现类
   Lock lock = new ReentrantLock();
   public void readFile(String fileMessage){
      lock.lock();// 上锁
      try{
         System.out.println(Thread.currentThread().getName()+"得到了锁,正在读取文件……");
         for(int i=0; i<fileMessage.length(); i++){
            System.out.print(fileMessage.charAt(i));
         }
         System.out.println();
         System.out.println("文件读取完毕!");
      }finally{
         System.out.println(Thread.currentThread().getName()+"释放了锁!");
         lock.unlock();
      }
   }
   public void demo(final String fileMessage){
      // 创建若干个线程
      ExecutorService service = Executors.newCachedThreadPool();
      // 提交20个任务
      for(int i=0; i<20; i++){
         service.execute(new Runnable() {
            @Override
            public void run() {
               readFile(fileMessage);
               try {
                  Thread.sleep(20);
               } catch (InterruptedException e) {
                  e.printStackTrace();
               }
            }
         });
      }
    // 释放线程池中的线程
      service.shutdown();
   }
}

Perbandingan antara Kunci dan disegerakkan

1 , fungsi

kunci dan disegerakkan ialah alatan yang digunakan dalam Java untuk menyelesaikan isu keselamatan benang.

2. Sumber

disegerakkan ialah kata kunci dalam Java.

kunci ialah antara muka yang disediakan dalam pakej JUC Antara muka ini mempunyai banyak kelas pelaksanaan, termasuk ReentrantLock (kunci reentrant) kami yang paling biasa digunakan.

3. Kekuatan kunci

disegerakkan boleh mengawal kekuatan kunci dalam dua cara:

Ubah suai kata kunci disegerakkan pada tahap kaedah.
Ubah suai pada blok kod.
Perbezaan dalam objek kunci:

Jika objek kunci ialah objek statik atau objek kelas, maka kunci ini ialah kunci global.
Objek kunci ialah objek tika biasa, dan skop kunci ini bergantung pada kitaran hayat tika ini.
Kekuatan kunci ditentukan oleh dua kaedah kunci() dan buka kunci(). Kod antara kedua-dua kaedah ini dijamin selamat untuk benang. Skop kunci bergantung pada kitaran hayat contoh kunci.

4. Fleksibiliti

Kunci lebih fleksibel daripada disegerakkan.

Kunci boleh memutuskan secara bebas masa untuk mengunci dan melepaskan kunci. Hanya panggil kaedah kunci() dan buka kunci() kunci.

Oleh kerana disegerakkan ialah kata kunci, ia tidak boleh melaksanakan kaedah kunci pertandingan tanpa menyekat Selepas satu utas memperoleh kunci, kunci lain hanya boleh menunggu sehingga utas itu dilepaskan sebelum mereka mempunyai peluang untuk memperoleh kunci.

5. Kunci adil dan kunci tidak adil

Kunci adil: Berbilang benang mendapatkan kunci mengikut urutan memohon kunci, dan utas akan terus memasuki baris gilir up, forever Hanya orang pertama dalam baris gilir boleh mendapatkan kunci.

Kelebihan: Semua rangkaian boleh mendapatkan sumber dan tidak akan mati kelaparan.
Kelemahan: Daya pemprosesan rendah, kecuali untuk utas pertama dalam baris gilir, semua utas lain akan disekat, dan kos CPU membangkitkan utas yang disekat adalah tinggi.
Kunci tidak adil: Apabila beberapa utas ingin memperoleh kunci, mereka akan terus mencuba untuk memperolehnya. Jika mereka tidak dapat memperolehnya, mereka akan memasuki baris gilir menunggu, mereka akan memperoleh kunci itu secara langsung.

Kelebihan: Ia boleh mengurangkan overhed utas pembangkit CPU, kecekapan pemprosesan keseluruhan akan lebih tinggi, dan CPU tidak perlu membangunkan semua utas, yang akan mengurangkan bilangan utas terjaga.
Kelemahan: Benang di tengah barisan mungkin tidak dapat memperoleh kunci atau tidak dapat memperoleh kunci untuk masa yang lama, dan akhirnya mati kelaparan.
Kunci menyediakan dua mekanisme: kunci adil dan kunci tidak adil (kunci tidak adil lalai).

disegerakkan ialah kunci yang tidak adil.

6 Sama ada hendak melepaskan kunci kerana pengecualian

Pelepasan kunci segerak adalah pasif dan hanya akan dikeluarkan apabila pelaksanaan blok kod segerak tamat. atau pengecualian berlaku.

Apabila pengecualian berlaku dalam kunci kunci, kunci yang diduduki tidak akan dilepaskan secara aktif secara manual dengan buka kunci(), jadi kami biasanya meletakkan blok kod penyegerakan ke dalam try-catch dan tulis buka kunci. akhirnya. () kaedah untuk mengelakkan kebuntuan.

7 Tentukan sama ada kunci boleh diperolehi

segerak tidak boleh.

kunci menyediakan kaedah kunci persaingan tidak menyekat trylock(), dan nilai pulangan adalah jenis Boolean. Ia menunjukkan bahawa ia digunakan untuk cuba memperoleh kunci: ia mengembalikan benar jika pemerolehan berjaya; ia mengembalikan palsu jika pemerolehan gagal.

8. Kaedah penjadualan

disegerakkan menggunakan tunggu, maklumkan dan maklumkanSemua kaedah objek objek itu sendiri, manakala kunci menggunakan Syarat untuk penjadualan antara utas.

9. Bolehkah ia terganggu?

disegerakkan hanya boleh menunggu kunci dilepaskan dan tidak boleh bertindak balas terhadap gangguan.

Anda boleh menggunakan interrupt() untuk mengganggu proses menunggu kunci.

10. Persembahan

Jika saingan tidak sengit, persembahan lebih kurang apabila saingan sengit, prestasi lock akan menjadi lebih baik.

Kunci juga boleh menggunakan readwritelock untuk memisahkan bacaan dan penulisan, meningkatkan kecekapan operasi membaca berbilang benang.

11. Peningkatan kunci disegerakkan

Blok kod disegerakkan dilaksanakan oleh sepasang arahan monitorenter/monitorexit. Pelaksanaan Monitor bergantung sepenuhnya pada kunci mutex di dalam sistem pengendalian Kerana ia memerlukan penukaran daripada mod pengguna kepada mod kernel, operasi penyegerakan adalah operasi berat yang tidak dibezakan.

Jadi kini JVM menyediakan tiga kunci berbeza: kunci berat sebelah, kunci ringan dan kunci berat.

Kunci berat sebelah:
Apabila tiada persaingan berlaku, penguncian berat sebelah digunakan secara lalai. Benang akan menggunakan operasi CAS untuk menetapkan ID benang pada pengepala objek untuk menunjukkan bahawa objek itu berat sebelah ke arah benang semasa.

Tujuan: Dalam banyak senario aplikasi, kitaran hayat kebanyakan objek akan dikunci oleh paling banyak satu utas Menggunakan kunci berat sebelah boleh mengurangkan overhed tanpa persaingan.

Kunci ringan:
JVM membandingkan threadID thread semasa dan threadID dalam pengepala objek Java untuk melihat jika ia tidak konsisten (contohnya, thread 2 mahu bersaing objek kunci), maka anda perlu menyemak rekod dalam pengepala objek Java Sama ada benang 1 masih hidup (kunci berat sebelah tidak akan dilepaskan secara aktif, jadi ia masih disimpan sebagai ID benang 1). , maka objek kunci masih merupakan kunci berat sebelah (ID benang dalam pengepala objek ialah benang 2);

Apabila urutan lain ingin mengakses sumber dengan kunci ringan, pengoptimuman kunci putaran akan digunakan untuk mengakses sumber.

Tujuan: Tidak banyak benang bersaing untuk objek kunci, dan benang tidak memegang kunci untuk masa yang lama. Kerana menyekat benang memerlukan CPU untuk memindahkan dari mod pengguna ke mod kernel, yang mahal Jika kunci dilepaskan sejurus selepas menyekat, keuntungan tidak berbaloi dengan kerugian itu, adalah lebih baik untuk tidak menyekat benang pada masa ini dan biarkan ia berputar untuk menunggu kunci dilepaskan.

Kunci heavyweight:
Jika putaran gagal, terdapat kebarangkalian tinggi bahawa pemilihan kendiri akan gagal lagi, jadi ia dinaik taraf terus kepada kunci heavyweight untuk menyekat benang dan mengurangkan penggunaan CPU.

Apabila kunci dinaik taraf kepada kunci kelas berat, benang yang belum menangkap kunci akan disekat dan memasuki baris gilir menyekat.

Atas ialah kandungan terperinci Cara menggunakan Lock dalam Java multithreading. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam