මම ThreadLocal
විචල්යයක් භාවිතා කළ යුත්තේ කවදාද ?
එය භාවිතා කරන්නේ කෙසේද?
මම ThreadLocal
විචල්යයක් භාවිතා කළ යුත්තේ කවදාද ?
එය භාවිතා කරන්නේ කෙසේද?
RequestUtils.getCurrentRequestThreadLocal()
. මෙය ඉතා අලංකාර යැයි නොකියන නමුත් බොහෝ විට ThreadLocal ඉතා අලංකාර නොවන බව මෙයින් කියැවේ.
Answers:
නූල්-ආරක්ෂිත නොවන යම් වස්තුවක් ඔබ සතුව ඇති විට (සහ පොදු) භාවිතා කළ හැකි එක් දෙයක් නම්, නමුත් ඔබට එම වස්තුවට ප්රවේශය සමමුහුර්ත කිරීමෙන් වැළකී සිටීමට අවශ්යය (මම ඔබ දෙස බලමි , සිම්පල් ඩේට් ෆෝමැට් ). ඒ වෙනුවට, එක් එක් නූල් වලට වස්තුව පිළිබඳ තමන්ගේම උදාහරණයක් දෙන්න.
උදාහරණයක් වශයෙන්:
public class Foo
{
// SimpleDateFormat is not thread-safe, so give one to each thread
private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
@Override
protected SimpleDateFormat initialValue()
{
return new SimpleDateFormat("yyyyMMdd HHmm");
}
};
public String formatIt(Date date)
{
return formatter.get().format(date);
}
}
SimpleDateFormat
. සමහර විට නූල් ආරක්ෂිත විකල්පයක් භාවිතා කිරීම වඩා හොඳය . ඔබ එකඟ නම් singletons නරකයි පසුව ThreadLocal
ඊටත් වඩා නරක ය.
ThreadLocal
ලබා දී ඇති දත්ත පිළිබඳ සඳහනක් බැවින් Thread
, ThreadLocal
යෙදුම් සේවාදායකවල නූල් තටාක භාවිතා කරමින් ඔබට පන්ති පැටවීමේ කාන්දුවීම් සමඟ අවසන් විය හැකිය . ඔබ යම් පිරිසිදු ගැන ඉතා පරෙස්සම් විය යුතුයි ThreadLocal
මනුස්සකම ඔබ get()
හෝ set()
භාවිතයෙන් ThreadLocal
ගේ remove()
ක්රමය.
ඔබ අවසන් වූ පසු ඔබ පිරිසිදු නොකරන්නේ නම්, යොදවා ඇති වෙබ් ඇප් එකක කොටසක් ලෙස පටවන ලද පංති සඳහා එය යොමු කරන ඕනෑම සඳහනක් ස්ථිර ගොඩවල පවතිනු ඇති අතර කිසි විටෙකත් කසළ එකතු නොවනු ඇත. වෙබ්අප් නැවත සේවයේ යෙදවීම / යෙදවීම Thread
ඔබේ වෙබ්අප් පන්තියට (එස්) එක් එක් යොමු කිරීම පිරිසිදු නොකරනු ඇත, මන්ද එය ඔබේ වෙබ්අප් Thread
සතු දෙයක් නොවන බැවිනි. සෑම අනුපිළිවෙලින්ම යෙදවීම පන්තියේ නව අවස්ථාවක් නිර්මාණය කරනු ඇති අතර එය කිසි විටෙකත් කසළ එකතු නොකෙරේ.
දෝෂය නිවැරදි කිරීම වෙනුවට java.lang.OutOfMemoryError: PermGen space
සමහර ගූග්ලිං වැඩිවීම නිසා ඔබ පසුව මතකයේ ව්යතිරේකයන්ගෙන් අවසන් වනු ඇත -XX:MaxPermSize
.
ඔබ මෙම ගැටළු වලට මුහුණ දෙන්නේ නම්, එක්ලිප්ස්ගේ මතක විශ්ලේෂකය සහ / හෝ ෆ්රෑන්ක් කීවියට්ගේ මාර්ගෝපදේශය සහ පසු විපරම් අනුගමනය කිරීමෙන් මෙම යොමු කිරීම් රඳවා ගන්නේ කුමන නූල් සහ පන්තියද යන්න ඔබට තීරණය කළ හැකිය .
යාවත්කාලීන කිරීම: ඇලෙක්ස් වාසුර්ගේ බ්ලොග් සටහන නැවත සොයා ගැනීම, එය මට ඇති ThreadLocal
ගැටළු කිහිපයක් සොයා ගැනීමට උපකාරී විය.
වත්මන් නූල් හා සම්බන්ධ යම් සන්දර්භයක් පවත්වා ගැනීම සඳහා බොහෝ රාමු ThreadLocals භාවිතා කරයි. නිදසුනක් ලෙස, වර්තමාන ගනුදෙනුව ත්රෙඩ්ලොකල් එකක ගබඩා කර ඇති විට, ඔබට එය සෑම ක්රම ඇමතුමකින්ම පරාමිතියක් ලෙස යැවීමට අවශ්ය නොවේ. වෙබ් යෙදුම් වර්තමාන ඉල්ලීම සහ සැසිය පිළිබඳ තොරතුරු ත්රෙඩ්ලොකල් එකක ගබඩා කළ හැකි අතර එමඟින් යෙදුමට පහසුවෙන් ප්රවේශ විය හැකිය. එන්නත් කරන ලද වස්තූන් සඳහා අභිරුචි විෂය පථයන් ක්රියාත්මක කිරීමේදී Guice සමඟ ඔබට ThreadLocals භාවිතා කළ හැකිය (ගයිස් හි පෙරනිමි සේවාදායක පරාසයන් බොහෝ විට ඒවා භාවිතා කරයි).
ThreadLocals යනු එක් ආකාරයක ගෝලීය විචල්යයන්ය (ඒවා එක් නූලකට පමණක් සීමා වී ඇති නිසා තරමක් අඩු නපුරක් වුවද), එබැවින් අනවශ්ය අතුරු ආබාධ සහ මතක කාන්දු වීම වළක්වා ගැනීමට ඒවා භාවිතා කිරීමේදී ඔබ ප්රවේශම් විය යුතුය. ඔබේ API නිර්මාණය කරන්න එවිට ThreadLocal අගයන් තවදුරටත් අවශ්ය නොවන විට ඒවා ස්වයංක්රීයව නිෂ්කාශනය වන අතර ඒපීඅයි වැරදි ලෙස භාවිතා කිරීමට නොහැකි වනු ඇත (උදාහරණයක් ලෙස මේ වගේ ). කේතය පිරිසිදු කිරීමට ThreadLocals භාවිතා කළ හැකි අතර සමහර දුර්ලභ අවස්ථාවන්හිදී යමක් වැඩ කිරීමට ඇති එකම ක්රමය ඒවාය (මගේ වර්තමාන ව්යාපෘතියට එවැනි අවස්ථා දෙකක් තිබුණි; ඒවා මෙහි "ස්ථිතික ක්ෂේත්ර සහ ගෝලීය විචල්යයන්" යටතේ ලේඛනගත කර ඇත ).
ජාවා හි, ඔබට එක් නූලකට වෙනස් විය හැකි දත්තයක් තිබේ නම්, ඔබේ තේරීම වන්නේ එම දත්ත අවශ්ය සෑම ක්රමයකටම (හෝ අවශ්ය විය හැකි) සම්මත කිරීම හෝ දත්ත නූල් සමඟ සම්බන්ධ කිරීමයි. ඔබගේ සියලු ක්රම දැනටමත් පොදු "සන්දර්භය" විචල්යයක් හරහා ගමන් කිරීමට අවශ්ය නම් සෑම තැනකම දත්ත සමුදාය ක්රියාත්මක කළ හැකිය.
එය එසේ නොවේ නම්, අතිරේක පරාමිතියක් සමඟ ඔබේ ක්රමයේ අත්සන අවුල් කිරීමට ඔබට අවශ්ය නොවනු ඇත. නූල් රහිත ලෝකයක, ඔබට ජාවා ගෝලීය විචල්යයකට සමාන ගැටළුව විසඳා ගත හැකිය. නූල් වචනයකින්, ගෝලීය විචල්යයකට සමාන වන්නේ නූල්-දේශීය විචල්යයකි.
'datum' is the singular form and 'data' is the plural form.
ජාවා කොන්කුරන්සි ඉන් ප්රැක්ටිස් පොතේ ඉතා හොඳ උදාහරණයක් තිබේ . කතෘ (කොහෙද යොෂුවා Bloch ), නූල් සිර නූල් ආරක්ෂාව සාක්ෂාත් කර ගැනීම ඉතා සරළ ක්රම වලින් එකක් වන අතර, ආකාරය විස්තර ThreadLocal නූල් සිර පවත්වාගෙන යාම වඩා විධිමත් ක්රමයක් වන්නේ ප්රචණ්ඩත්වයයි. අවසානයේදී ඔහු එය ගෝලීය විචල්යයන් ලෙස භාවිතා කිරීමෙන් මිනිසුන්ට එය අනිසි ලෙස භාවිතා කළ හැකි ආකාරය පැහැදිලි කරයි.
මම සඳහන් කළ පොතෙන් පෙළ පිටපත් කර ඇති නමුත් 3.10 කේතය අස්ථානගත වී ඇති බැවින් ThreadLocal භාවිතා කළ යුත්තේ කොතැනද යන්න තේරුම් ගැනීම එතරම් වැදගත් නොවේ.
විකෘති සිංගල්ටන් හෝ ගෝලීය විචල්යයන් මත පදනම් වූ මෝස්තර බෙදාගැනීම වැළැක්වීම සඳහා නූල්-දේශීය විචල්යයන් බොහෝ විට භාවිතා කරයි. නිදසුනක් ලෙස, එක් එක් නූල් යෙදුමක් සෑම ක්රමයකටම සම්බන්ධතාවයක් නොපැවැත්වීම සඳහා ආරම්භයේදීම ආරම්භ කරන ලද ගෝලීය දත්ත සමුදා සම්බන්ධතාවයක් පවත්වා ගත හැකිය. ජේඩීබීසී සම්බන්ධතා නූල්-ආරක්ෂිත නොවිය හැකි බැවින්, අතිරේක සම්බන්ධීකරණයකින් තොරව ගෝලීය සම්බන්ධතාවයක් භාවිතා කරන බහු තෙරපුම් යෙදුමක් නූල් ආරක්ෂිත නොවේ. ලැයිස්තුගත කිරීමේ 3.10 හි ConnectionHolder හි මෙන්, JDBC සම්බන්ධතාවය ගබඩා කිරීම සඳහා ThreadLocal භාවිතා කිරීමෙන්, සෑම නූලකටම තමන්ගේම සම්බන්ධතාවයක් ඇත.
යෙදුම් රාමු ක්රියාත්මක කිරීමේදී ThreadLocal බහුලව භාවිතා වේ. උදාහරණයක් ලෙස, J2EE බහාලුම් ගනුදෙනු සන්දර්භයක් EJB ඇමතුමක කාලසීමාව සඳහා ක්රියාත්මක වන නූල් සමඟ සම්බන්ධ කරයි. ගනුදෙනු සන්දර්භය දරණ ස්ථිතික නූල්-දේශීය භාවිතයෙන් මෙය පහසුවෙන් ක්රියාත්මක කළ හැකිය: රාමු කේතයට දැනට ක්රියාත්මක වන ගනුදෙනුව කුමක්ද යන්න තීරණය කිරීමට අවශ්ය වූ විට, එය මෙම ThreadLocal වෙතින් ගනුදෙනු සන්දර්භය ලබා ගනී. මෙය පහසු වන අතර එය ක්රියාත්මක කිරීමේ සන්දර්භය පිළිබඳ තොරතුරු සෑම ක්රමයකටම යැවීමේ අවශ්යතාවය අඩු කරයි, නමුත් මෙම යාන්ත්රණය භාවිතා කරන ඕනෑම කේතයක් රාමුවට සම්බන්ධ කරයි.
නූල් සිරගත කිරීමේ දේපල ගෝලීය විචල්යයන් භාවිතා කිරීමේ බලපත්රයක් ලෙස හෝ “සැඟවුණු” ක්රම තර්ක නිර්මාණය කිරීමේ මාධ්යයක් ලෙස සැලකීමෙන් ThreadLocal අපයෝජනය කිරීම පහසුය. ගෝලීය විචල්යයන් මෙන්, නූල්-දේශීය විචල්යයන්ට නැවත භාවිතයෙන් ract ත් විය හැකි අතර පංති අතර සැඟවුණු කප්ලිං හඳුන්වා දිය හැකි අතර එබැවින් ඒවා ප්රවේශමෙන් භාවිතා කළ යුතුය.
අත්යවශ්යයෙන්ම, වත්මන් නූල් මත යැපීමට ඔබට විචල්යයක වටිනාකමක් අවශ්ය වන විට සහ වෙනත් ආකාරයකින් නූල් වලට අගය ඇමිණීම ඔබට පහසු නොවේ (උදාහරණයක් ලෙස, උප පංති නූල්).
සාමාන්ය අවස්ථාවක් නම්, වෙනත් කේතයක් මඟින් ඔබේ කේතය ක්රියාත්මක වන නූල් නිර්මාණය කර ඇති අතර, උදා: සර්වට් බහාලුමක්, හෝ ThreadLocal භාවිතා කිරීම වඩාත් අර්ථවත් වන්නේ ඔබේ විචල්යය පසුව “එහි තාර්කික ස්ථානයේ” (විචල්යයකට වඩා) නූල් උප පංතියක හෝ වෙනත් හැෂ් සිතියමක එල්ලීම).
මගේ වෙබ් අඩවියේ, මට උනන්දුවක් දැක්විය හැකි ThreadLocal භාවිතා කළ යුත්තේ කෙසේද යන්න පිළිබඳ තවත් සාකච්ඡා සහ උදාහරණ ඇත.
ඔබට නූල් අංකයක් අවශ්ය වන සමගාමී ඇල්ගොරිතම වල එක් එක් නූලට “නූල් හැඳුනුම්පතක්” ඇමිණිය හැකි ක්රමයක් ලෙස සමහර අය ThreadLocal භාවිතා කිරීමට උපදෙස් දෙයි (උදා: හර්ලිහි සහ ෂාවිට් බලන්න). එවැනි අවස්ථාවන්හිදී, ඔබට සැබවින්ම ප්රතිලාභයක් ලැබේදැයි පරීක්ෂා කරන්න!
ජාවා හි ThreadLocal JDK 1.2 හි හඳුන්වා දී ඇති නමුත් පසුව ThDLocal විචල්යය මත වර්ගයේ ආරක්ෂාව හඳුන්වා දීම සඳහා JDK 1.5 හි ජනනය කරන ලදි.
ThreadLocal Thread විෂය පථය සමඟ සම්බන්ධ කළ හැකිය, Thread විසින් ක්රියාත්මක කරන සියලුම කේත වලට ThreadLocal විචල්යයන් වෙත ප්රවේශය ඇත, නමුත් නූල් දෙකකට එකිනෙක දැකිය නොහැක ThreadLocal විචල්යය.
සෑම ත්රෙඩ් එකකම ත්රෙඩ්ලොකල් විචල්යයේ සුවිශේෂී පිටපතක් ඇති අතර එය සාමාන්යයෙන් හෝ කිසියම් ව්යතිරේකයක් හේතුවෙන් නූල් අවසන් වූ පසු හෝ මිය ගිය පසු කසළ එකතු කිරීමට සුදුසුකම් ලබයි. එම ThreadLocal විචල්යයට වෙනත් සජීවී යොමු කිරීම් නොමැත.
ජාවා හි ThreadLocal විචල්යයන් සාමාන්යයෙන් පන්තිවල පෞද්ගලික ස්ථිතික ක්ෂේත්ර වන අතර නූල් තුළ එහි තත්වය පවත්වා ගනී.
තව දුරටත් කියවන්න: ජාවා හි ThreadLocal - උදාහරණ වැඩසටහන සහ නිබන්ධනය
ප්රලේඛනය එය ඉතා හොඳින් පවසයි: "[නූල්-දේශීය විචල්යයකට] ප්රවේශ වන සෑම නූලකටම (එහි ලබා ගැනීමේ හෝ සැකසීමේ ක්රමය හරහා) විචල්යයේ ස්වාධීනව ආරම්භ කරන ලද පිටපතක් ඇත".
සෑම නූල් එකකටම යම්කිසි පිටපතක් තිබිය යුතු විට ඔබ එකක් භාවිතා කරයි. පෙරනිමියෙන්, දත්ත නූල් අතර බෙදා ගැනේ.
Threadlocal විචල්යය භාවිතා කළ හැකි අවස්ථා දෙකක් -
1- අපට නූල් සමඟ තත්වය සම්බන්ධ කිරීමේ අවශ්යතාවයක් ඇති විට (උදා: පරිශීලක හැඳුනුම්පතක් හෝ ගනුදෙනු හැඳුනුම්පතක්). එය සාමාන්යයෙන් සිදුවන්නේ සේවාදායකයකු වෙත යන සෑම ඉල්ලීමකටම අද්විතීය ගනුදෙනු ID එකක් ඇති වෙබ් යෙදුමක් සමඟ ය.
// This class will provide a thread local variable which
// will provide a unique ID for each thread
class ThreadId {
// Atomic integer containing the next thread ID to be assigned
private static final AtomicInteger nextId = new AtomicInteger(0);
// Thread local variable containing each thread's ID
private static final ThreadLocal<Integer> threadId =
ThreadLocal.<Integer>withInitial(()-> {return nextId.getAndIncrement();});
// Returns the current thread's unique ID, assigning it if necessary
public static int get() {
return threadId.get();
}
}
මෙහි දී ඉනිටීයල් සමඟ ක්රමය ලැම්බඩා ප්රකාශනය භාවිතයෙන් ක්රියාත්මක වන බව සලකන්න.
2- තවත් භාවිත අවස්ථාවක් වන්නේ අපට නූල් ආරක්ෂිත අවස්ථාවක් ලබා ගැනීමට අවශ්ය වූ විට සහ සමමුහුර්තකරණය සමඟ කාර්ය සාධන පිරිවැය වැඩි බැවින් සමමුහුර්තකරණය භාවිතා කිරීමට අපට අවශ්ය නැත. එවැනි එක් අවස්ථාවක් වන්නේ සිම්පල් ඩේට් ෆෝමැට් භාවිතා කරන විටය. සිම්පල් ඩේට් ෆෝමැට් නූල් ආරක්ෂිත නොවන බැවින් එය නූල් ආරක්ෂිත කිරීමට යාන්ත්රණයක් සැපයිය යුතුය.
public class ThreadLocalDemo1 implements Runnable {
// threadlocal variable is created
private static final ThreadLocal<SimpleDateFormat> dateFormat = new ThreadLocal<SimpleDateFormat>(){
@Override
protected SimpleDateFormat initialValue(){
System.out.println("Initializing SimpleDateFormat for - " + Thread.currentThread().getName() );
return new SimpleDateFormat("dd/MM/yyyy");
}
};
public static void main(String[] args) {
ThreadLocalDemo1 td = new ThreadLocalDemo1();
// Two threads are created
Thread t1 = new Thread(td, "Thread-1");
Thread t2 = new Thread(td, "Thread-2");
t1.start();
t2.start();
}
@Override
public void run() {
System.out.println("Thread run execution started for " + Thread.currentThread().getName());
System.out.println("Date formatter pattern is " + dateFormat.get().toPattern());
System.out.println("Formatted date is " + dateFormat.get().format(new Date()));
}
}
ජාවා 8 නිකුතුවේ සිට, ආරම්භ කිරීමට තවත් ප්රකාශන ක්රමයක් තිබේ ThreadLocal
:
ThreadLocal<Cipher> local = ThreadLocal.withInitial(() -> "init value");
ජාවා 8 නිකුතුව තෙක් ඔබට පහත සඳහන් දේ කිරීමට සිදු විය:
ThreadLocal<String> local = new ThreadLocal<String>(){
@Override
protected String initialValue() {
return "init value";
}
};
තවද, භාවිතා කරන පන්තියේ ක්ෂණික ක්රමය (ඉදිකිරීම්කරු, කර්මාන්තශාලා ක්රමය) ThreadLocal
කිසිදු පරාමිතියක් නොගන්නේ නම්, ඔබට සරලවම ක්රම යොමු භාවිතා කළ හැකිය (ජාවා 8 හි හඳුන්වා දී ඇත):
class NotThreadSafe {
// no parameters
public NotThreadSafe(){}
}
ThreadLocal<NotThreadSafe> container = ThreadLocal.withInitial(NotThreadSafe::new);
සටහන:
ඔබ java.util.function.Supplier
ලැම්බඩා පසුකර යන බැවින් ඇගයීම කම්මැලි වන අතර එය ඇගයීමට ලක් කරනු ThreadLocal#get
ලබන්නේ කැඳවූ විට පමණක් වන නමුත් වටිනාකම කලින් තක්සේරු කර නොමැත.
ThreadLocal රටාව සමඟ ඔබ ඉතා ප්රවේශම් විය යුතුය. ෆිල් වැනි ප්රධාන පහළ පැති කිහිපයක් ඇත, නමුත් සඳහන් නොකළ එකක් නම්, ත්රෙඩ්ලොකල් සන්දර්භය සැකසෙන කේතය “නැවත ඇතුල් නොවන” බවට වග බලා ගැනීමයි.
තොරතුරු සකසන කේතය දෙවන හෝ තුන්වන වතාවට ක්රියාත්මක වන විට අයහපත් දේ සිදුවිය හැකිය, මන්ද ඔබ බලාපොරොත්තු නොවූ විට ඔබේ ත්රෙඩ් එකේ තොරතුරු විකෘති වීමට පටන් ගත හැකිය. එබැවින් ඔබ නැවත සැකසීමට පෙර ThreadLocal තොරතුරු සකසා නොමැති බවට වග බලා ගන්න.
ThreadLocal
රටාවක් නොවේ . ඔබ එසේ කළහොත් F(){ member=random(); F2(); write(member); }
සහ F2 නව අගයක් සහිත සාමාජිකයා අභිබවා ගියහොත් , පැහැදිලිවම write(member)
ඔබ random()
සංස්කරණය කළ අංකය තවදුරටත් ලියන්නේ නැත . මෙය වචනාර්ථයෙන් සාමාන්ය බුද්ධියකි. ඒ හා සමානව, ඔබ එසේ කරන්නේ නම් F(){ F(); }
, ඔබගේ අනන්ත පුඩුවට වාසනාව! මෙය සෑම තැනකම සත්ය වන අතර එය විශේෂිත නොවේ ThreadLocal
.
කවදා ද?
වස්තුවක් නූල්-ආරක්ෂිත නොවන විට, පරිමාණයට බාධා කරන සමමුහුර්තකරණය වෙනුවට, සෑම වස්තුවකටම එක් වස්තුවක් ලබා දී එය නූල් විෂය පථය ලෙස තබා ගන්න, එය ThreadLocal වේ. බොහෝ විට භාවිතා කරන නමුත් නූල් ආරක්ෂිත නොවන වස්තු වලින් එකක් වන්නේ දත්ත සමුදා සම්බන්ධතාවය සහ ජේඑම්එස් සම්බන්ධතාවයයි.
කෙසේද ?
එක් උදාහරණයක් නම්, මෙම සම්බන්ධතා වස්තු ThreadLocal විචල්යයන්හි තබා ගැනීමෙන් තිරය පිටුපස ගනුදෙනු කළමනාකරණය කිරීම සඳහා වසන්ත රාමුව ThreadLocal දැඩි ලෙස භාවිතා කරයි. ඉහළ මට්ටමක, ගනුදෙනුවක් ආරම්භ කළ විට එය සම්බන්ධතාවය ලබා ගනී (සහ ස්වයංක්රීය බැඳීම අක්රීය කරයි) සහ එය ThreadLocal හි තබා ගනී. තවදුරටත් db ඇමතුම් වලදී එය db සමඟ සන්නිවේදනය කිරීමට එකම සම්බන්ධතාවයක් භාවිතා කරයි. අවසානයේදී, එය ThreadLocal වෙතින් සම්බන්ධතාවය ගෙන ගනුදෙනුව සිදු කරයි (හෝ පෙරළීම) සම්බන්ධතාවය නිදහස් කරයි.
MDC නඩත්තු කිරීම සඳහා log4j ද ThreadLocal භාවිතා කරයි.
ThreadLocal
විවිධ නූල් අතර බෙදා නොගත යුතු යම් තත්වයක් ඔබට අවශ්ය විට එය ප්රයෝජනවත් වේ, නමුත් එය එක් එක් නූල් වලින් එහි මුළු ජීවිත කාලය තුළම ප්රවේශ විය යුතුය.
උදාහරණයක් ලෙස, එක් එක් ඉල්ලීම වෙනස් නූලකින් සපයන වෙබ් යෙදුමක් ගැන සිතන්න. සෑම ඉල්ලීමක් සඳහාම ඔබට දත්ත කැබැල්ලක් කිහිප වතාවක් අවශ්ය යැයි සිතන්න, එය ගණනය කිරීමට තරමක් මිල අධිකය. කෙසේ වෙතත්, එන සෑම ඉල්ලීමක් සඳහාම එම දත්ත වෙනස් වන්නට ඇත, එයින් අදහස් කරන්නේ ඔබට සරල හැඹිලියක් භාවිතා කළ නොහැකි බවයි. මෙම ගැටළුවට සරල, ඉක්මන් විසඳුමක් වනුයේ මෙම ThreadLocal
දත්ත වලට විචල්ය රඳවා ගැනීමේ ප්රවේශයක් තිබීමයි, එවිට ඔබට එය ගණනය කළ යුත්තේ එක් එක් ඉල්ලීම සඳහා එක් වරක් පමණි. ඇත්ත වශයෙන්ම, මෙම ගැටළුව භාවිතයෙන් තොරව විසඳිය හැකි ThreadLocal
නමුත් මම එය නිදර්ශන අරමුණු සඳහා සකස් කළෙමි.
එය ThreadLocal
අත්යවශ්යයෙන්ම ගෝලීය රාජ්යයක ස්වරූපයක් බව මතක තබා ගන්න . එහි ප්රති As ලයක් වශයෙන්, එය වෙනත් බොහෝ ඇඟවුම් ඇති අතර එය භාවිතා කළ යුත්තේ අනෙක් සියලුම විසඳුම් සලකා බැලීමෙන් පසුව පමණි.
ThreadLocal
වස්තුවකට විවිධ වස්තූන් වෙනස් තත්වයක් තිබිය යුතු නම්, ඔබට වස්තු ක්ෂේත්රයක් ලෙස භාවිතා කළ හැකිය ...
ThreadLocal
ගෝලීය වශයෙන් ප්රවේශ විය හැකි අනිසි භාවිතයන් කිහිපයකට මම බොහෝ විට පැකිලී ඇත . ඔබ කී පරිදි, එය තවමත් දෘශ්යතාව සීමා කරන පන්ති ක්ෂේත්රයක් ලෙස භාවිතා කළ හැකිය.
මෙහි ඇත්ත වශයෙන්ම අළුත් කිසිවක් නැත, නමුත් ThreadLocal
වෙබ් යෙදුමක බීන් වලංගුකරණය භාවිතා කිරීමේදී එය ඉතා ප්රයෝජනවත් බව මම අද සොයා ගතිමි . වලංගු කිරීමේ පණිවිඩ දේශීයකරණය වී ඇත, නමුත් පෙරනිමියෙන් භාවිතා කරයි Locale.getDefault()
. ඔබට Validator
වෙනත් ආකාරයකින් වින්යාසගත කළ හැකිය MessageInterpolator
, නමුත් Locale
ඔබ ඇමතූ විට නියම කිරීමට ක්රමයක් නොමැත validate
. එබැවින් ඔබට ස්ථිතික ThreadLocal<Locale>
(හෝ වඩා හොඳ, ඔබට අවශ්ය විය හැකි වෙනත් දේ සහිත සාමාන්ය බහාලුමක් සාදාගෙන ThreadLocal
ඔබේ අභිමතය පරිදි එය MessageInterpolator
තෝරා ගත Locale
හැකිය. ඊළඟ පියවර වන්නේ ServletFilter
සැසි අගයක් භාවිතා කරන ලිපියක් ලිවීම හෝ request.getLocale()
පෙදෙසි සහ ගබඩාව තෝරා ගැනීමයි. එය ඔබේ ThreadLocal
යොමු දැක්වීමේදී.
Ununknown (google) විසින් සඳහන් කළ පරිදි, එහි භාවිතය වන්නේ ගෝලීය විචල්යයක් නිර්වචනය කිරීමයි, එහි සඳහන් අගය එක් එක් ත්රෙඩ් එකෙහි අද්විතීය විය හැකිය. එහි භාවිතයන් සාමාන්යයෙන් වර්තමාන ක්රියාත්මක කිරීමේ නූල් සමඟ සම්බන්ධ වී ඇති යම් ආකාරයක සන්දර්භීය තොරතුරු ගබඩා කිරීම අවශ්ය වේ.
ජාවා ඊඊ නොදන්නා පන්ති වෙත පරිශීලක අනන්යතාවය ලබා දීමට අපි එය ජාවා ඊඊ පරිසරයක භාවිතා කරමු (HttpSession හෝ EJB SessionContext වෙත ප්රවේශය නොමැත). ආරක්ෂාව පදනම් කරගත් මෙහෙයුම් සඳහා අනන්යතාවය භාවිතා කරන කේතය මේ ආකාරයෙන්, සෑම ක්රම ඇමතුමකදීම පැහැදිලිවම සම්මත නොකර, ඕනෑම තැනක සිට අනන්යතාවයට ප්රවේශ විය හැකිය.
බොහෝ ජාවා ඊඊ ඇමතුම් වල ඉල්ලීම් / ප්රතිචාර චක්රය මෙම භාවිතය පහසු කරයි.
සමමුහුර්ත නොවන ක්රමයේ බහු නූල් මගින් විකෘති වස්තුවට ප්රවේශ වීම ThreadLocal විසින් සහතික කරනු ඇත, එයින් අදහස් වන්නේ විකෘති වස්තුව ක්රමවේදය තුළ වෙනස් කළ නොහැකි බවට පත් කිරීමයි.
මෙය සාක්ෂාත් කරගනු ලබන්නේ එක් එක් නූල් සඳහා විකෘති වස්තුවකට නව අවස්ථාවක් ලබා දීමෙන් එය වෙත ප්රවේශ වීමට උත්සාහ කරන්න. එබැවින් එය එක් එක් නූල් සඳහා දේශීය පිටපතකි. මෙය දේශීය විචල්යයක් ලෙස ප්රවේශ විය හැකි ක්රමයක නිදර්ශන විචල්යයක් බවට පත්කිරීමේ යම්කිසි කඩාවැටීමකි. ඔබ දන්නා ක්රමය අනුව දේශීය විචල්යය ලබා ගත හැක්කේ නූල් වලට පමණි, එක් වෙනසක් වන්නේ; ක්රමවේදය ක්රියාත්මක වූ පසු දේශීය විචල්යයන් නූල් වෙත නොපවතින අතර, අප විසින් පිරිසිදු කරන තෙක් නූල්ලොකල් සමඟ බෙදාගත හැකි විකෘති වස්තුවක් විවිධ ක්රම හරහා ලබා ගත හැකිය.
අර්ථ දැක්වීම අනුව:
ජාවා හි ThreadLocal පන්තිය මඟින් එකම නූල් එකකින් පමණක් කියවිය හැකි හා ලිවිය හැකි විචල්යයන් නිර්මාණය කිරීමට ඔබට හැකි වේ. මේ අනුව, නූල් දෙකක් එකම කේතය ක්රියාත්මක කළත්, කේතයට ThreadLocal විචල්යයක් ගැන සඳහනක් තිබුණත්, නූල් දෙක එකිනෙකට ThreadLocal විචල්යයන් දැකිය නොහැක.
Thread
ජාවා වල ඇති සෑම එකක්ම එහි අඩංගු වේ ThreadLocalMap
.
කොහෙද
Key = One ThreadLocal object shared across threads.
value = Mutable object which has to be used synchronously, this will be instantiated for each thread.
ThreadLocal ලබා ගැනීම:
දැන් ThreadLocal සඳහා ආවරණ පංතියක් සාදන්න, එය විකෘති වස්තුව පහත පරිදි රඳවා තබා ගනී (සමඟ හෝ නැතිව) initialValue()
) .
දැන් මෙම එතීමේ යන්ත්රය සහ සැකසුම විකෘති වස්තුව වෙනුවට නූල් ස්ථානීය උදාහරණ මත ක්රියා කරයි.
Threadlocal හි getter () හි threadlocalmap හි කිසිදු අගයක් සොයාගත නොහැකි නම් Thread
; එවිට එය නූල් සම්බන්ධව එහි පුද්ගලික පිටපත ලබා ගැනීම සඳහා ආරම්භක අගය () ඉල්ලා සිටී.
class SimpleDateFormatInstancePerThread {
private static final ThreadLocal<SimpleDateFormat> dateFormatHolder = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd") {
UUID id = UUID.randomUUID();
@Override
public String toString() {
return id.toString();
};
};
System.out.println("Creating SimpleDateFormat instance " + dateFormat +" for Thread : " + Thread.currentThread().getName());
return dateFormat;
}
};
/*
* Every time there is a call for DateFormat, ThreadLocal will return calling
* Thread's copy of SimpleDateFormat
*/
public static DateFormat getDateFormatter() {
return dateFormatHolder.get();
}
public static void cleanup() {
dateFormatHolder.remove();
}
}
දැන් wrapper.getDateFormatter()
අමතනු ඇති threadlocal.get()
අතර එමඟින් මෙම (ත්රෙඩ්ලොකල්) උදාහරණය currentThread.threadLocalMap
අඩංගු වේ .
ඔව්, ඊට අනුරූප ත්රෙඩ්ලොකල් නිදසුන සඳහා අගය (සිම්පල් ඩේට් ෆෝමැට්) ආපසු ලබා දෙන්නේ නම්,
මෙම ත්රෙඩ්ලොකල් උදාහරණය සමඟ සිතියම එක් කරන්න, ආරම්භක අගය ().
මෙම විකෘති පංතිය මත හෙරුවිත් නූල් ආරක්ෂාව; එක් එක් නූල් මඟින් තමන්ගේම විකෘති නිදසුනක් සමඟ ක්රියා කරන නමුත් එකම ThreadLocal නිදසුන සමඟ ක්රියා කරයි. ක්රම සියළුම නූල් යතුර ලෙස එකම ThreadLocal උදාහරණය බෙදාගනු ඇත, නමුත් අගය ලෙස වෙනස් SimpleDateFormat උදාහරණය.
https://github.com/skanagavelu/yt.tech/blob/master/src/ThreadLocalTest.java
විකෘති සිංගල්ටන් හෝ ගෝලීය විචල්යයන් මත පදනම් වූ මෝස්තර බෙදාගැනීම වැළැක්වීම සඳහා නූල්-දේශීය විචල්යයන් බොහෝ විට භාවිතා කරයි.
ඔබ සම්බන්ධතා තටාකයක් භාවිතා නොකරන විට එක් එක් නූල් සඳහා වෙනම JDBC සම්බන්ධතාවයක් ඇති කිරීම වැනි අවස්ථා වලදී එය භාවිතා කළ හැකිය.
private static ThreadLocal<Connection> connectionHolder
= new ThreadLocal<Connection>() {
public Connection initialValue() {
return DriverManager.getConnection(DB_URL);
}
};
public static Connection getConnection() {
return connectionHolder.get();
}
ඔබ getConnection අමතන විට, එය එම ත්රෙඩ් එක හා සම්බන්ධිත සම්බන්ධතාවයක් ලබා දෙනු ඇත. ඔබට නූල් අතර බෙදා ගැනීමට අවශ්ය නොවන දිනය හැඩතල, ගනුදෙනු සන්දර්භය වැනි වෙනත් ගුණාංග සමඟද මෙය කළ හැකිය.
ඔබට ඒ සඳහා දේශීය විචල්යයන් ද භාවිතා කළ හැකි නමුත් මෙම සම්පත් සාමාන්යයෙන් නිර්මාණයේ කාලය ගත කරයි, එබැවින් ඔබ ඔවුන් සමඟ යම් ව්යාපාර තර්කනයක් සිදු කරන සෑම විටම ඒවා නැවත නැවතත් නිර්මාණය කිරීමට ඔබට අවශ්ය නැත. කෙසේ වෙතත්, ThreadLocal අගයන් නූල් වස්තුව තුළම ගබඩා කර ඇති අතර නූල් කසළ එකතු කළ විගසම මෙම අගයන් ද නැති වී යයි.
මෙම සබැඳිය ThreadLocal භාවිතය ඉතා හොඳින් පැහැදිලි කරයි.
භාවිතා කිරීම සඳහා 3 ඒවායින් කවරක්ද ඇත පන්ති සහකාරියක් එක් භාවිතය වන හොඳම multithread කේතය, දී SimpleDateFormat වැනි ThreadLocal
සිදුවීම්
1- යෙදුම මන්දගාමී වන අගුළු හෝ සමමුහුර්ත කිරීමේ යාන්ත්රණයේ ආධාරයෙන් සමාන කොටස් වස්තුවක් භාවිතා කිරීම
2- ලෙස භාවිතා කරමින් දේශීය වස්තුව ක්රමයක් තුල
මෙම තත්වය තුළ, අපට නූල් 4 ක් තිබේ නම්, එක් එක් ක්රමයට 1000 වතාවක් අමතන්න, එවිට අපට
4000 සිම්පල් ඩේට් ෆෝමැට් වස්තුවක් නිර්මාණය කර ඇති අතර ඒවා මකා දැමීමට ජී.සී.
3- ThreadLocal භාවිතා කිරීම
අපි 4 නූල් ඇති වුවහොත් අපි දුන් එක් SimpleDateFormat උදාහරණයක් එක් එක් නූල්
අපට එසේ 4 නූල් , 4 වස්තූන් SimpleDateFormat ය.
අගුළු යාන්ත්රණය සහ වස්තු නිර්මාණය හා විනාශ කිරීම අවශ්ය නොවේ. (හොඳ කාල සංකීර්ණත්වය සහ අවකාශයේ සංකීර්ණතාව)
මෙම ThreadLocalජාවා පන්තිය මඟින් එකම නූල් පමණක් කියවිය හැකි හා ලිවිය හැකි විචල්යයන් නිර්මාණය කිරීමට ඔබට හැකි වේ. මේ අනුව, නූල් දෙකක් එකම කේතය ක්රියාත්මක කළත්, කේතයට ThreadLocal විචල්යයක් ගැන සඳහනක් තිබුණත්, නූල් දෙක එකිනෙකට ThreadLocal විචල්යයන් දැකිය නොහැක.
[යොමුව සඳහා] හවුල් වස්තුවක යාවත්කාලීන ගැටළු විසඳීමට ThreadLocal හට නොහැක. එකම ත්රෙඩ් එකේ ඇති සියලුම මෙහෙයුම් මගින් බෙදා ගන්නා ස්ථිතික ත්රෙඩ්ලොකල් වස්තුවක් භාවිතා කිරීම රෙකමදාරු කරනු ලැබේ. [අනිවාර්ය] ඉවත් කිරීමේ () ක්රමය ThreadLocal විචල්යයන් විසින් ක්රියාත්මක කළ යුතුය, විශේෂයෙන් නූල් බොහෝ විට නැවත භාවිතා කරන නූල් තටාක භාවිතා කරන විට. එසේ නොමැති නම්, එය පසුකාලීන ව්යාපාරික තර්කනයට බලපාන අතර මතක කාන්දු වීම වැනි අනපේක්ෂිත ගැටළු ඇති කළ හැකිය.
හැඹිලිය, යම් වේලාවක ඔබට එකම අගය ගණනය කිරීමට සිදු වන අතර එමඟින් අවසාන යෙදවුම් කට්ටලයක් ක්රමයකට ගබඩා කිරීමෙන් සහ ප්රති result ලය මඟින් ඔබට කේතය වේගවත් කළ හැකිය. Thread Local Storage භාවිතා කිරීමෙන් ඔබ අගුළු දැමීම ගැන සිතීමෙන් වළකින්න.
ThreadLocal යනු නූල් සඳහා පමණක් හුදකලා ගබඩා ඉඩක් ලබා දීම සඳහා JVM විසින් විශේෂයෙන් සපයන ලද ක්රියාකාරීත්වයකි. නිදසුනක් ලෙස විෂය පථයේ විචල්යය පන්තියේ එක් අවස්ථාවකට පමණක් බැඳී ඇත. සෑම වස්තුවකටම එහි එකම අගයන් ඇති අතර ඒවාට එකිනෙකාගේ අගය නොපෙනේ. ThreadLocal විචල්යයන් පිළිබඳ සංකල්පය ද එසේමය, ඒවා නූල් වලට දේශීය වේ වස්තු අවස්ථා අර්ථයෙන් එය නිර්මාණය කළ එක හැර වෙනත් නූල්, එය නොපෙනේ. මෙහි බලන්න
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
public class ThreadId {
private static final AtomicInteger nextId = new AtomicInteger(1000);
// Thread local variable containing each thread's ID
private static final ThreadLocal<Integer> threadId = ThreadLocal.withInitial(() -> nextId.getAndIncrement());
// Returns the current thread's unique ID, assigning it if necessary
public static int get() {
return threadId.get();
}
public static void main(String[] args) {
new Thread(() -> IntStream.range(1, 3).forEach(i -> {
System.out.println(Thread.currentThread().getName() + " >> " + new ThreadId().get());
})).start();
new Thread(() -> IntStream.range(1, 3).forEach(i -> {
System.out.println(Thread.currentThread().getName() + " >> " + new ThreadId().get());
})).start();
new Thread(() -> IntStream.range(1, 3).forEach(i -> {
System.out.println(Thread.currentThread().getName() + " >> " + new ThreadId().get());
})).start();
}
}
Threadlocal විසින් ශුන්ය පිරිවැය සමඟ වස්තූන් නැවත භාවිතා කිරීමේ හැකියාව ලබා ගැනීම සඳහා ඉතා පහසු ක්රමයක් සපයයි.
සෑම යාවත්කාලීන දැනුම්දීමකදීම විකෘති හැඹිලියේ රූපයක් බහු නූල් නිර්මාණය කරන තත්වයක් මට තිබුණි.
මම සෑම ත්රෙඩ් එකකම ත්රෙඩ්ලොකල් එකක් භාවිතා කළ අතර, පසුව සෑම නූල් එකකටම පැරණි රූපය නැවත සැකසීමට අවශ්ය වන අතර පසුව සෑම යාවත්කාලීන දැනුම්දීමකම හැඹිලියෙන් එය යාවත්කාලීන කරන්න.
වස්තු තටාක වලින් නැවත නැවත භාවිතා කළ හැකි වස්තූන් ඒවාට නූල් ආරක්ෂණ පිරිවැය සම්බන්ධ කර ඇති අතර මෙම ප්රවේශයට කිසිවක් නොමැත.
ThreadLocal විචල්යය පිළිබඳ හැඟීමක් ලබා ගැනීමට මෙම කුඩා උදාහරණය උත්සාහ කරන්න:
public class Book implements Runnable {
private static final ThreadLocal<List<String>> WORDS = ThreadLocal.withInitial(ArrayList::new);
private final String bookName; // It is also the thread's name
private final List<String> words;
public Book(String bookName, List<String> words) {
this.bookName = bookName;
this.words = Collections.unmodifiableList(words);
}
public void run() {
WORDS.get().addAll(words);
System.out.printf("Result %s: '%s'.%n", bookName, String.join(", ", WORDS.get()));
}
public static void main(String[] args) {
Thread t1 = new Thread(new Book("BookA", Arrays.asList("wordA1", "wordA2", "wordA3")));
Thread t2 = new Thread(new Book("BookB", Arrays.asList("wordB1", "wordB2")));
t1.start();
t2.start();
}
}
නූල් බුක්ඒ පළමුව සිදු කරන්නේ නම් කොන්සෝලය ප්රතිදානය:
ප්රති ult ල බුක්ඒ: 'වර්ඩ්ඒ 1, වර්ඩ්ඒ 2, වර්ඩ්ඒ 3'.
ප්රති Book ලය BookB: 'wordB1, wordB2'.
නූල් BookB පළමුව සිදු කරන්නේ නම් කොන්සෝලය ප්රතිදානය:
ප්රති ult ලය BookB: 'wordB1, wordB2'.
ප්රති Book ල පොත: 'wordA1, wordA2, wordA3'.