మరొక రకమైన థ్రెడ్ పూల్ "కాష్". ఇటువంటి థ్రెడ్ కొలనులు స్థిరమైన వాటి వలె సాధారణంగా ఉపయోగించబడతాయి.
పేరు సూచించినట్లుగా, ఈ రకమైన థ్రెడ్ పూల్ థ్రెడ్లను క్యాష్ చేస్తుంది. కొత్త టాస్క్లను నిర్వహించడానికి ఆ థ్రెడ్లను మళ్లీ ఉపయోగించడం కోసం ఇది ఉపయోగించని థ్రెడ్లను పరిమిత సమయం వరకు సజీవంగా ఉంచుతుంది. మనకు కొంత సహేతుకమైన కాంతి పని ఉన్నప్పుడు అలాంటి థ్రెడ్ పూల్ ఉత్తమం.
"కొంత సహేతుకమైన మొత్తం" యొక్క అర్థం చాలా విస్తృతమైనది, అయితే అటువంటి పూల్ ప్రతి సంఖ్యలో పనులకు తగినది కాదని మీరు తెలుసుకోవాలి. ఉదాహరణకు, మనం ఒక మిలియన్ టాస్క్లను సృష్టించాలనుకుంటున్నాము. ప్రతి ఒక్కటి చాలా తక్కువ సమయం తీసుకున్నప్పటికీ, మేము ఇప్పటికీ అసమంజసమైన వనరులను ఉపయోగిస్తాము మరియు పనితీరును దిగజార్చుకుంటాము. అమలు సమయం అనూహ్యంగా ఉన్నప్పుడు, ఉదాహరణకు, I/O టాస్క్లతో పాటు మనం అలాంటి పూల్లను కూడా నివారించాలి.
హుడ్ కింద, ThreadPoolExecutor కన్స్ట్రక్టర్ కింది వాదనలతో పిలువబడుతుంది:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
కింది విలువలు ఆర్గ్యుమెంట్లుగా కన్స్ట్రక్టర్కు పంపబడతాయి:
పరామితి | విలువ |
---|---|
corePoolSize ( ఎగ్జిక్యూటర్ సర్వీస్ ప్రారంభమైనప్పుడు ఎన్ని థ్రెడ్లు సిద్ధంగా ఉంటాయి (ప్రారంభమవుతాయి) ) | 0 |
గరిష్ట పూల్సైజ్ ( ఎగ్జిక్యూటర్ సర్వీస్ సృష్టించగల గరిష్ట సంఖ్యలో థ్రెడ్లు ) | పూర్ణాంకం.MAX_VALUE |
KeepAliveTime ( కోర్పూల్సైజ్ కంటే థ్రెడ్ల సంఖ్య ఎక్కువగా ఉంటే, విముక్తి పొందిన థ్రెడ్ నాశనమయ్యే ముందు జీవించే సమయం ) | 60L |
యూనిట్ (సమయం యూనిట్లు) | సమయ యూనిట్.SECONDS |
వర్క్ క్యూ (క్యూ అమలు) | కొత్త సింక్రోనస్ క్యూ<రన్నబుల్>() |
మరియు మేము ThreadFactory యొక్క మా స్వంత అమలును సరిగ్గా అదే విధంగా పాస్ చేయవచ్చు .
SynchronousQueue గురించి మాట్లాడుకుందాం
సమకాలీకరణ బదిలీ యొక్క ప్రాథమిక ఆలోచన చాలా సరళమైనది మరియు ప్రతిస్పందించేది (అంటే, అంతర్ దృష్టి లేదా ఇంగితజ్ఞానం అది తప్పు అని మీకు చెబుతుంది): మరొక థ్రెడ్ మూలకాన్ని స్వీకరించినట్లయితే మాత్రమే మీరు ఒక మూలకాన్ని క్యూలో జోడించవచ్చు. అదే సమయం లో. మరో మాటలో చెప్పాలంటే, సింక్రోనస్ క్యూలో టాస్క్లు ఉండవు, ఎందుకంటే కొత్త టాస్క్ వచ్చిన వెంటనే, ఎగ్జిక్యూటింగ్ థ్రెడ్ ఇప్పటికే టాస్క్ను ఎంచుకుంది .

కొత్త టాస్క్ క్యూలోకి ప్రవేశించినప్పుడు, పూల్లో ఉచిత యాక్టివ్ థ్రెడ్ ఉంటే, అది టాస్క్ను ఎంచుకుంటుంది. అన్ని థ్రెడ్లు బిజీగా ఉంటే, కొత్త థ్రెడ్ సృష్టించబడుతుంది.
కాష్ చేసిన పూల్ సున్నా థ్రెడ్లతో ప్రారంభమవుతుంది మరియు పూర్ణాంకం.MAX_VALUE థ్రెడ్లకు సంభావ్యంగా పెరుగుతుంది . ముఖ్యంగా, కాష్ చేయబడిన థ్రెడ్ పూల్ పరిమాణం సిస్టమ్ వనరుల ద్వారా మాత్రమే పరిమితం చేయబడింది.
సిస్టమ్ వనరులను సంరక్షించడానికి, కాష్ చేయబడిన థ్రెడ్ పూల్స్ ఒక నిమిషం పాటు నిష్క్రియంగా ఉన్న థ్రెడ్లను తీసివేస్తాయి.
ఆచరణలో ఇది ఎలా పని చేస్తుందో చూద్దాం. మేము వినియోగదారు అభ్యర్థనను మోడల్ చేసే టాస్క్ క్లాస్ని సృష్టిస్తాము:
public class Task implements Runnable {
int taskNumber;
public Task(int taskNumber) {
this.taskNumber = taskNumber;
}
@Override
public void run() {
System.out.println("Processed user request #" + taskNumber + " on thread " + Thread.currentThread().getName());
}
}
ప్రధాన పద్ధతిలో, మేము కొత్తCachedThreadPoolని సృష్టించి , ఆపై అమలు కోసం 3 టాస్క్లను జోడిస్తాము . ఇక్కడ మేము మా సేవ యొక్క స్థితిని ప్రింట్ చేస్తాము (1) .
తరువాత, మేము 30 సెకన్ల పాటు పాజ్ చేసి, మరొక పనిని ప్రారంభించి, స్థితిని ప్రదర్శిస్తాము (2) .
ఆ తర్వాత, మేము మా ప్రధాన థ్రెడ్ను 70 సెకన్లపాటు పాజ్ చేసి, స్థితి (3) ని ప్రింట్ చేసి , మళ్లీ 3 టాస్క్లను జోడించి, మళ్లీ స్థితి (4) ని ప్రింట్ చేస్తాము .
టాస్క్ను జోడించిన వెంటనే మేము స్థితిని ప్రదర్శించే ప్రదేశాలలో, అప్-టు-డేట్ అవుట్పుట్ కోసం మేము ముందుగా 1-సెకన్ నిద్రను జోడిస్తాము.
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 3; i++) {
executorService.submit(new Task(i));
}
TimeUnit.SECONDS.sleep(1);
System.out.println(executorService); //(1)
TimeUnit.SECONDS.sleep(30);
executorService.submit(new Task(3));
TimeUnit.SECONDS.sleep(1);
System.out.println(executorService); //(2)
TimeUnit.SECONDS.sleep(70);
System.out.println(executorService); //(3)
for (int i = 4; i < 7; i++) {
executorService.submit(new Task(i));
}
TimeUnit.SECONDS.sleep(1);
System.out.println(executorService); //(4)
executorService.shutdown();
మరియు ఇక్కడ ఫలితం ఉంది:
పూల్-1-థ్రెడ్-2 థ్రెడ్లో వినియోగదారు అభ్యర్థన #1
ప్రాసెస్ చేయబడింది పూల్-1-థ్రెడ్-3 థ్రెడ్లో వినియోగదారు అభ్యర్థన #2 ప్రాసెస్ చేయబడింది
(1) java.util.concurrent .ThreadPoolExecutor@f6f4d33[రన్నింగ్, పూల్ సైజు = 3, యాక్టివ్ థ్రెడ్లు = 0, క్యూలో ఉన్న టాస్క్లు = 0, పూర్తయిన టాస్క్లు = 3]
pool-1-thread-2 థ్రెడ్లో #3 ప్రాసెస్ చేయబడిన వినియోగదారు అభ్యర్థన
(2) java.util.concurrent. ThreadPoolExecutor@f6f4d33[రన్నింగ్, పూల్ సైజు = 3, యాక్టివ్ థ్రెడ్లు = 0, క్యూలో ఉన్న టాస్క్లు = 0, పూర్తయిన టాస్క్లు = 4]
(3) java.util.concurrent.ThreadPoolExecutor@f6f4d33[రన్నింగ్, పూల్ పరిమాణం = 0 , క్యూలో ఉన్న పనులు = 0, పూర్తయిన పనులు = 4]
పూల్-1-థ్రెడ్-4 థ్రెడ్లో వినియోగదారు అభ్యర్థన #4 ప్రాసెస్ చేయబడింది
పూల్-1-థ్రెడ్-5 థ్రెడ్లో వినియోగదారు అభ్యర్థన #5 ప్రాసెస్ చేయబడింది
pool-1-thread-4 థ్రెడ్
(4) java.util.concurrent.ThreadPoolExecutor@f6f4d33పై వినియోగదారు అభ్యర్థన #6 ప్రాసెస్ చేయబడింది[రన్నింగ్, పూల్ పరిమాణం = 2, సక్రియ థ్రెడ్లు = 0, క్యూలో ఉన్న టాస్క్లు = 0, పూర్తయిన టాస్క్లు = 7]
ప్రతి దశను పరిశీలిద్దాం:
దశ | వివరణ |
---|---|
1 (3 పూర్తయిన టాస్క్ల తర్వాత) | మేము 3 థ్రెడ్లను సృష్టించాము మరియు ఈ మూడు థ్రెడ్లలో 3 టాస్క్లు అమలు చేయబడ్డాయి. స్థితి ప్రదర్శించబడినప్పుడు, మొత్తం 3 పనులు పూర్తయ్యాయి మరియు థ్రెడ్లు ఇతర పనులను చేయడానికి సిద్ధంగా ఉంటాయి. |
2 (30-సెకన్ల విరామం మరియు మరొక పనిని అమలు చేసిన తర్వాత) | 30 సెకన్ల నిష్క్రియ తర్వాత, థ్రెడ్లు ఇప్పటికీ సజీవంగా ఉన్నాయి మరియు పనుల కోసం వేచి ఉన్నాయి. మిగిలిన లైవ్ థ్రెడ్ల పూల్ నుండి తీసిన థ్రెడ్పై మరొక పని జోడించబడుతుంది మరియు అమలు చేయబడుతుంది. పూల్కు కొత్త థ్రెడ్ జోడించబడలేదు. |
3 (70 సెకన్ల విరామం తర్వాత) | పూల్ నుండి దారాలు తీసివేయబడ్డాయి. టాస్క్లను అంగీకరించడానికి ఎలాంటి థ్రెడ్లు సిద్ధంగా లేవు. |
4 (మరో 3 టాస్క్లను అమలు చేసిన తర్వాత) | మరిన్ని పనులు స్వీకరించిన తర్వాత, కొత్త థ్రెడ్లు సృష్టించబడ్డాయి. ఈసారి కేవలం రెండు థ్రెడ్లు 3 టాస్క్లను ప్రాసెస్ చేయగలిగాయి. |
సరే, ఇప్పుడు మీరు మరొక రకమైన కార్యనిర్వాహక సేవ యొక్క లాజిక్తో పరిచయం కలిగి ఉన్నారు.
ఎగ్జిక్యూటర్స్ యుటిలిటీ క్లాస్ యొక్క ఇతర పద్ధతులతో సారూప్యతతో , newCachedThreadPool పద్ధతిలో థ్రెడ్ఫ్యాక్టరీ వస్తువును వాదనగా తీసుకునే ఓవర్లోడ్ వెర్షన్ కూడా ఉంది .
GO TO FULL VERSION