Apabila menggunakan kumpulan benang, selepas memanggil kaedah shutdown(), kumpulan benang tidak lagi akan menerima tugas pelaksanaan baharu. Walau bagaimanapun, tugasan yang diletakkan dalam baris gilir tugas sebelum memanggil kaedah shutdown() masih perlu dilaksanakan. Kaedah ini ialah kaedah bukan menyekat dan akan kembali serta-merta selepas dipanggil Ia tidak akan menunggu semua tugasan dalam baris gilir tugasan dilaksanakan sebelum kembali. Mari kita lihat pada kod sumber kaedah shutdown(), seperti yang ditunjukkan di bawah.
public void shutdown() { //获取线程池的全局锁 final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { //检查是否有关闭线程池的权限 checkShutdownAccess(); //将当前线程池的状态设置为SHUTDOWN advanceRunState(SHUTDOWN); //中断Worker线程 interruptIdleWorkers(); //为ScheduledThreadPoolExecutor调用钩子函数 onShutdown(); // hook for } finally { //释放线程池的全局锁 mainLock.unlock(); } //尝试将状态变为TERMINATED tryTerminate(); }
Secara amnya, kod kaedah shutdown() adalah agak mudah untuk menyemak sama ada terdapat kebenaran untuk menutup kumpulan benang Jika ada kebenaran, ia menyemak semula sama ada terdapat kebenaran untuk mengganggu utas kerja Jika tidak, kebenaran, SecurityException akan dilemparkan, kodnya adalah seperti berikut.
//检查是否有关闭线程池的权限 checkShutdownAccess(); //将当前线程池的状态设置为SHUTDOWN advanceRunState(SHUTDOWN); //中断Worker线程 interruptIdleWorkers();
Antaranya, kod pelaksanaan kaedah checkShutdownAccess() adalah seperti berikut.
private void checkShutdownAccess() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPermission(shutdownPerm); final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { for (Worker w : workers) security.checkAccess(w.thread); } finally { mainLock.unlock(); } } }
Adalah mudah untuk memahami kod kaedah checkShutdownAccess(), iaitu untuk mengesan sama ada anda mempunyai kebenaran untuk menutup kumpulan benang, semasa kunci global kumpulan benang digunakan.
Seterusnya, kita melihat kod sumber kaedah advanceRunState(int), seperti yang ditunjukkan di bawah.
private void advanceRunState(int targetState) { for (;;) { int c = ctl.get(); if (runStateAtLeast(c, targetState) || ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c)))) break; } }
Logik keseluruhan kaedah advanceRunState(int) adalah untuk menentukan sama ada keadaan kumpulan benang semasa ialah keadaan yang ditetapkan dalam kaedah shutdown() adalah MATUTUP. ia kembali secara langsung ;Jika ia tidak MATUTUP, tetapkan status kumpulan utas semasa kepada MATUTUP.
Seterusnya, mari lihat kaedah interruptIdleWorkers() yang dipanggil oleh kaedah showdown(), seperti yang ditunjukkan di bawah.
private void interruptIdleWorkers() { interruptIdleWorkers(false); }
Seperti yang anda lihat, kaedah interruptIdleWorkers() memanggil kaedah interruptIdleWorkers(boolean) Teruskan melihat kod sumber kaedah interruptIdleWorkers(boolean), seperti yang ditunjukkan di bawah.
private void interruptIdleWorkers(boolean onlyOne) { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { for (Worker w : workers) { Thread t = w.thread; if (!t.isInterrupted() && w.tryLock()) { try { t.interrupt(); } catch (SecurityException ignore) { } finally { w.unlock(); } } if (onlyOne) break; } } finally { mainLock.unlock(); } }
Logik keseluruhan kod di atas ialah: dapatkan kunci global kumpulan benang, kitaran melalui semua utas pekerja, mengesan sama ada utas itu terganggu, jika ia tidak terganggu, dan utas Pekerja mendapatkan kunci, laksanakan kaedah Interrupt benang dan lepaskan kunci yang diperolehi oleh benang. Pada masa ini, jika parameter OnlyOne adalah benar, keluar dari gelung. Jika tidak, gelung melalui semua benang pekerja dan lakukan operasi yang sama. Akhirnya, kunci global kumpulan benang dilepaskan.
Seterusnya, mari kita lihat kaedah shutdownNow().
Jika kaedah shutdownNow() kumpulan benang dipanggil, kumpulan benang tidak lagi akan menerima tugas pelaksanaan baharu dan juga akan membuang tugasan yang sedia ada dalam baris gilir tugas . Benang Pekerja pelaksana juga akan terganggu serta-merta Pada masa yang sama, kaedah ini akan kembali serta-merta, iaitu senarai tugasan yang dibuang dalam baris gilir tugasan.
Kod sumber kaedah shutdownNow() adalah seperti berikut.
public List<Runnable> shutdownNow() { List<Runnable> tasks; final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { //检查是否有关闭权限 checkShutdownAccess(); //设置线程池的状态为STOP advanceRunState(STOP); //中断所有的Worker线程 interruptWorkers(); //将任务队列中的任务移动到tasks集合中 tasks = drainQueue(); } finally { mainLock.unlock(); } /尝试将状态变为TERMINATED tryTerminate(); //返回tasks集合 return tasks; }
Logik keseluruhan kod sumber kaedah shutdownNow() pada asasnya sama dengan kaedah shutdown(), kecuali kaedah shutdownNow() menetapkan status kumpulan benang kepada STOP, mengganggu semua rangkaian Pekerja dan tugasan Semua tugasan dalam baris gilir dialihkan ke koleksi tugasan dan dikembalikan.
Seperti yang anda lihat, apabila kaedah shutdownNow() mengganggu semua utas, ia memanggil kaedah interruptWorkers() Seterusnya, kita akan melihat kod sumber kaedah interruptWorkers(), seperti yang ditunjukkan di bawah.
private void interruptWorkers() { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { for (Worker w : workers) w.interruptIfStarted(); } finally { mainLock.unlock(); } }
Logik kaedah interruptWorkers() adalah agak mudah, iaitu untuk mendapatkan kunci global kumpulan benang, kitaran melalui semua benang pekerja, mengganggu benang dalam urutan, dan akhirnya melepaskan global kunci kolam benang.
Di dalam kaedah interruptWorkers(), kaedah interruptIfStarted() kelas Worker sebenarnya dipanggil untuk mengganggu urutan Mari kita lihat kod sumber kaedah interruptIfStarted() kelas Worker, sebagai ditunjukkan di bawah.
void interruptIfStarted() { Thread t; if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) { try { t.interrupt(); } catch (SecurityException ignore) { } } }
Didapati bahawa ia pada asasnya memanggil kaedah interrupt() kelas Thread untuk mengganggu thread.
Apabila kumpulan utas memanggil kaedah awaitTermination(panjang, Unit Masa), urutan pemanggil akan disekat sehingga status kumpulan utas ditukar kepada TERMINATED Kembali, atau kembali apabila tempoh tamat masa telah dicapai. Seterusnya, mari lihat kod sumber kaedah awaitTermination(long, TimeUnit), seperti yang ditunjukkan di bawah.
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { //获取距离超时时间剩余的时长 long nanos = unit.toNanos(timeout); //获取Worker线程的的全局锁 final ReentrantLock mainLock = this.mainLock; //加锁 mainLock.lock(); try { for (;;) { //当前线程池状态为TERMINATED状态,会返回true if (runStateAtLeast(ctl.get(), TERMINATED)) return true; //达到超时时间,已超时,则返回false if (nanos <= 0) return false; //重置距离超时时间的剩余时长 nanos = termination.awaitNanos(nanos); } } finally { //释放锁 mainLock.unlock(); } }
Logik keseluruhan kod di atas ialah: mula-mula dapatkan kunci eksklusif utas Worker, dan kemudian gelung untuk menentukan sama ada kumpulan utas semasa sudah berada dalam keadaan TERMINAT Jika ya, kembalikan benar secara langsung, jika tidak, semak sama ada ia telah tamat masa Jika ia telah tamat masa, kembalikan palsu. Jika ia tidak tamat masa, tetapkan semula masa yang tinggal sebelum tamat masa. Seterusnya, masukkan kitaran seterusnya dan semak semula sama ada kumpulan benang semasa berada dalam keadaan TERMINAT Jika ya, kembalikan benar jika tidak, semak sama ada ia telah tamat masa, kembalikan palsu. Jika ia tidak tamat masa, tetapkan semula masa yang tinggal sebelum tamat masa. Gelung ini berterusan sehingga status kumpulan benang menjadi DITAMATKAN atau telah tamat masa.
Atas ialah kandungan terperinci Bagaimana untuk menutup kumpulan benang Java dengan anggun?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!