6. Ano ang Cancarenzi?
Ang Concurrency ay isang library ng klase sa Java na naglalaman ng mga espesyal na klase na na-optimize para sa pagtatrabaho sa maraming thread. Ang mga klase na ito ay kinokolekta sa isang paketejava.util.concurrent
. Maaari silang hatiin ayon sa eskematiko ayon sa functionality tulad ng sumusunod: Concurrent Collections - isang set ng mga koleksyon na mas mahusay na gumagana sa isang multi-threaded na kapaligiran kaysa sa karaniwang mga unibersal na koleksyon mula java.util
sa package. Sa halip na isang pangunahing wrapper Collections.synchronizedList
na may pagharang sa access sa buong koleksyon, ginagamit ang mga lock sa mga segment ng data, o ang trabaho ay na-optimize para sa parallel na pagbabasa ng data gamit ang mga algorithm na walang paghihintay. Mga Queue - hindi humaharang at humaharang sa mga pila na may suporta sa multi-threading. Ang mga hindi nakaharang na pila ay idinisenyo para sa bilis at operasyon nang hindi hinaharangan ang mga thread. Ginagamit ang pagharang sa mga pila kapag kailangan mong "pabagalin" ang mga thread na "Producer" o "Consumer" kung ang ilang kundisyon ay hindi natutugunan, halimbawa, ang pila ay walang laman o umaapaw, o walang libreng "Consumer". Ang mga synchronizer ay mga auxiliary utilities para sa pag-synchronize ng mga thread. Ang mga ito ay isang makapangyarihang sandata sa "parallel" computing. Executors - naglalaman ng mahuhusay na frameworks para sa paglikha ng mga thread pool, pag-iskedyul ng mga asynchronous na gawain at pagkuha ng mga resulta. Locks - kumakatawan sa mga alternatibo at mas nababaluktot na mekanismo ng pag-synchronize ng thread kumpara sa synchronized
mga wait
pangunahing notify
. Atomics - mga klase na may suporta para sa atomic operations sa primitives at reference. Pinagmulan:notifyAll
7. Anong mga klase mula sa Kankarensi ang alam mo?
Ang sagot sa tanong na ito ay ganap na nakasaad sa artikulong ito . Hindi ko nakikita ang punto sa muling pag-print ng lahat dito, kaya magbibigay lang ako ng mga paglalarawan sa mga klase na nagkaroon ako ng karangalan na madaling pamilyar sa aking sarili. ConcurrentHashMap<K, V> - Hindi tuladHashtable
at hinaharangan synhronized
sa HashMap
, ang data ay ipinakita sa anyo ng mga segment, na nahahati sa mga hash ng mga key. Bilang resulta, ang data ay ina-access ng mga segment sa halip na sa pamamagitan ng isang bagay. Bilang karagdagan, ang mga iterator ay kumakatawan sa data para sa isang tiyak na tagal ng panahon at hindi nagtatapon ng ConcurrentModificationException
. AtomicBoolean, AtomicInteger, AtomicLong, AtomicIntegerArray, AtomicLongArray - Paano kung sa isang klase kailangan mong i-synchronize ang access sa isang simpleng variable ng uri int
? Maaari kang gumamit ng mga construct na may synchronized
, at kapag gumagamit ng atomic operations set/get
, volatile
. Ngunit maaari kang gumawa ng mas mahusay sa pamamagitan ng paggamit ng mga bagong klase Atomic*
. Dahil sa paggamit ng CAS, ang mga pagpapatakbo sa mga klase na ito ay mas mabilis kaysa sa pag-synchronize sa pamamagitan ng synchronized/volatile
. Dagdag pa, may mga pamamaraan para sa atomic na pagdaragdag sa pamamagitan ng isang naibigay na halaga, pati na rin ang pagtaas/pagbawas.
8. Paano gumagana ang klase ng ConcurrentHashMap?
Sa oras ng pagpapakilala nito,ConcurrentHashMap
kailangan ng mga developer ng Java ang sumusunod na pagpapatupad ng hash map:
- Kaligtasan ng thread
- Walang mga kandado sa buong mesa habang ina-access ito
- Ito ay kanais-nais na walang mga kandado ng talahanayan kapag nagsasagawa ng isang read operation
ConcurrentHashMap
ay ang mga sumusunod:
-
Mga elemento ng mapa
Hindi tulad ng mga elemento
HashMap
,Entry
inConcurrentHashMap
ay ipinahayag bilangvolatile
. Isa itong mahalagang feature, dahil din sa mga pagbabago sa JMM .static final class HashEntry<K, V> { final K key; final int hash; volatile V value; final HashEntry<K, V> next; HashEntry(K key, int hash, HashEntry<K, V> next, V value) { this .key = key; this .hash = hash; this .next = next; this .value = value; } @SuppressWarnings("unchecked") static final <K, V> HashEntry<K, V>[] newArray(int i) { return new HashEntry[i]; } }
-
Pag-andar ng hash
ConcurrentHashMap
ginagamit din ang isang pinahusay na pag-andar ng hashing.Hayaan mong ipaalala ko sa iyo kung ano ito sa
HashMap
JDK 1.2:static int hash(int h) { h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); }
Bersyon mula sa ConcurrentHashMap JDK 1.5:
private static int hash(int h) { h += (h << 15) ^ 0xffffcd7d; h ^= (h >>> 10); h += (h << 3); h ^= (h >>> 6); h += (h << 2) + (h << 14); return h ^ (h >>> 16); }
Bakit kailangang gawing mas kumplikado ang hash function? Ang mga talahanayan sa isang hash na mapa ay may haba na tinutukoy ng kapangyarihan ng dalawa. Para sa mga hash code na ang mga binary na representasyon ay hindi naiiba sa mababa at mataas na posisyon, magkakaroon tayo ng mga banggaan. Ang pagpapataas ng pagiging kumplikado ng hash function ay malulutas lamang ang problemang ito, na binabawasan ang posibilidad ng mga banggaan sa mapa.
-
Mga segment
Ang mapa ay nahahati sa N iba't ibang mga segment (16 bilang default, ang maximum na halaga ay maaaring 16 bits at isang kapangyarihan ng dalawa). Ang bawat segment ay isang thread-safe na talahanayan ng mga elemento ng mapa. Ang pagpapataas ng bilang ng mga segment ay hihikayat sa mga pagpapatakbo ng pagbabago na sumasaklaw sa maramihang mga segment, na binabawasan ang posibilidad ng pagharang sa runtime.
-
ConcurrencyLevel
Ang parameter na ito ay nakakaapekto sa paggamit ng memory card at ang bilang ng mga segment sa card.
Ang bilang ng mga segment ay pipiliin bilang ang pinakamalapit na kapangyarihan ng dalawang mas mataas sa concurrencyLevel. Ang pagpapababa sa concurrencyLevel ay ginagawang mas malamang na ang mga thread ay haharangin ang mga segment ng mapa kapag nagsusulat. Ang labis na pagpapahalaga sa tagapagpahiwatig ay humahantong sa hindi mahusay na paggamit ng memorya. Kung isang thread lang ang magbabago sa mapa, at magbabasa ang iba, inirerekomendang gamitin ang value 1.
-
Kabuuan
Kaya, ang mga pangunahing bentahe at mga tampok ng pagpapatupad
ConcurrentHashMap
:hashmap
Ang mapa ay may interface ng pakikipag-ugnayan na katulad ng- Ang mga operasyon sa pagbabasa ay hindi nangangailangan ng mga kandado at isinasagawa nang magkatulad
- Ang mga pagpapatakbo ng pagsulat ay madalas ding maisagawa nang magkatulad nang walang pagharang
- Kapag lumilikha, ang kinakailangan ay ipinahiwatig
concurrencyLevel
, na tinutukoy sa pamamagitan ng pagbabasa at pagsulat ng mga istatistika - Ang mga elemento ng mapa ay may halagang
value
idineklara bilangvolatile
9. Ano ang klase ng Lock?
Upang kontrolin ang pag-access sa isang nakabahaging mapagkukunan, maaari naming gamitin ang mga kandado bilang alternatibo sa naka-synchronize na operator. Naka-package ang locking functionality sajava.util.concurrent.locks
. Una, sinusubukan ng thread na i-access ang nakabahaging mapagkukunan. Kung ito ay libre, pagkatapos ay isang lock ang inilalagay sa thread. Kapag nakumpleto na ang gawain, ilalabas ang lock sa nakabahaging mapagkukunan. Kung ang mapagkukunan ay hindi libre at may nakalagay na lock dito, maghihintay ang thread hanggang sa maalis ang lock na ito. Ang mga klase ng lock ay nagpapatupad ng isang interface Lock
na tumutukoy sa mga sumusunod na pamamaraan:
void lock():
naghihintay hanggang sa makuha ang lockboolean tryLock():
sumusubok na kumuha ng lock; kung makuha ang lock, babalik ito ng totoo . Kung ang lock ay hindi nakuha, ito ay nagbabalik ng false . Hindi tulad ng pamamaraan,lock()
hindi ito naghihintay na makakuha ng isang lock kung ang isa ay hindi magagamitvoid unlock():
tinatanggal ang lockCondition newCondition():
ibinabalik ang bagayCondition
na nauugnay sa kasalukuyang lock
lock()
, at pagkatapos ng pagtatapos ng pagtatrabaho sa mga nakabahaging mapagkukunan, ang pamamaraan ay tinatawag na unlock()
, na naglalabas ng lock. Ang bagay ay Condition
nagpapahintulot sa iyo na pamahalaan ang pagharang. Bilang isang patakaran, upang gumana sa mga lock, isang klase ReentrantLock
mula sa package ang ginagamit. java.util.concurrent.locks.
Ang klase na ito ay nagpapatupad ng interface Lock
. Tingnan natin ang paggamit ng Java Lock API gamit ang isang maliit na programa bilang isang halimbawa: Kaya, sabihin nating mayroon tayong klase Resource
na may ilang pamamaraan at pamamaraan na ligtas sa thread kung saan hindi kinakailangan ang kaligtasan ng thread.
public class Resource {
public void doSomething(){
// пусть здесь происходит работа с базой данных
}
public void doLogging(){
// потокобезопасность для логгирования нам не требуется
}
}
Ngayon ay kumuha tayo ng isang klase na nagpapatupad ng interface Runnable
at gumagamit ng mga pamamaraan ng klase Resource
.
public class SynchronizedLockExample implements Runnable{
// экземпляр класса Resource для работы с методами
private Resource resource;
public SynchronizedLockExample(Resource r){
this.resource = r;
}
@Override
public void run() {
synchronized (resource) {
resource.doSomething();
}
resource.doLogging();
}
}
Ngayon ay muling isulat natin ang programa sa itaas gamit ang Lock API sa halip na ang synchronized
.
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
// класс для работы с Lock API. Переписан с приведенной выше программы,
// но уже без использования ключевого слова synchronized
public class ConcurrencyLockExample implements Runnable{
private Resource resource;
private Lock lock;
public ConcurrencyLockExample(Resource r){
this.resource = r;
this.lock = new ReentrantLock();
}
@Override
public void run() {
try {
// лочим на 10 секунд
if(lock.tryLock(10, TimeUnit.SECONDS)){
resource.doSomething();
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
//убираем лок
lock.unlock();
}
// Для логгирования не требуется потокобезопасность
resource.doLogging();
}
}
Tulad ng nakikita mo mula sa programa, ginagamit namin ang pamamaraan tryLock()
upang matiyak na ang thread ay naghihintay lamang para sa isang tiyak na tagal ng oras. Kung hindi ito makakuha ng isang lock sa bagay, ito ay mag-log at lalabas lamang. Isa pang mahalagang punto. Dapat kang gumamit ng isang bloke try-finally
upang matiyak na ang lock ay ilalabas kahit na ang pamamaraan doSomething()
ay naghagis ng isang pagbubukod. Mga Pinagmulan:
11. Ano ang mutex?
Ang mutex ay isang espesyal na bagay para sa pag-synchronize ng mga thread/proseso. Maaaring tumagal ng dalawang estado - abala at libre. Upang pasimplehin, ang mutex ay isang boolean variable na kumukuha ng dalawang value: busy (true) at libre (false). Kapag nais ng isang thread ang eksklusibong pagmamay-ari ng isang bagay, minarkahan nito ang mutex nito bilang abala, at kapag natapos na itong magtrabaho dito, minarkahan nito ang mutex nito bilang libre. Ang isang mutex ay naka-attach sa bawat bagay sa Java. Ang Java machine lang ang may direktang access sa mutex. Ito ay nakatago mula sa programmer.12. Ano ang monitor?
Ang monitor ay isang espesyal na mekanismo (isang piraso ng code) - isang add-on sa mutex, na nagsisiguro ng tamang operasyon dito. Pagkatapos ng lahat, hindi sapat na markahan na ang bagay ay abala; dapat din nating tiyakin na ang ibang mga thread ay hindi subukang gamitin ang abalang bagay. Sa Java, ang monitor ay ipinatupad gamit ang keywordsynchronized
. Kapag sumulat kami ng isang naka-synchronize na bloke, pinapalitan ito ng Java compiler ng tatlong piraso ng code:
- Sa simula ng block
synchronized
, idinaragdag ang code na nagmamarka sa mutex bilang abala. - Sa dulo ng block,
synchronized
may idinagdag na code na nagmamarka sa mutex bilang libre. - Bago ang block,
synchronized
idinagdag ang code na sumusuri kung abala ang mutex, pagkatapos ay dapat hintayin ng thread na mailabas ito.
GO TO FULL VERSION