สำหรับผู้ที่ได้ยินคำว่า Java Core เป็นครั้งแรก สิ่งเหล่านี้ถือเป็นรากฐานพื้นฐานของภาษา ด้วยความรู้นี้ คุณสามารถไปฝึกงาน/ฝึกงานได้อย่างปลอดภัย
คำถามเหล่านี้จะช่วยให้คุณทบทวนความรู้ก่อนการสัมภาษณ์หรือเรียนรู้สิ่งใหม่ๆ สำหรับตัวคุณเอง หากต้องการเพิ่มทักษะ การ ปฏิบัติ เรียนที่JavaRush บทความต้นฉบับ ลิงก์ไปยังส่วนอื่น ๆ : Java Core คำถามสัมภาษณ์ ตอนที่ 1 Java Core คำถามสัมภาษณ์งาน ตอนที่ 3
โปรแกรมตัวอย่าง:
เหตุใดจึงควรหลีกเลี่ยงวิธีการสรุป ()
เราทุกคนรู้ข้อความที่ว่าตัวfinalize()
รวบรวมขยะเรียกเมธอดก่อนที่จะปล่อยหน่วยความจำที่วัตถุครอบครอง นี่คือตัวอย่างโปรแกรมที่พิสูจน์ว่าfinalize()
ไม่รับประกันการเรียกใช้เมธอด:
public class TryCatchFinallyTest implements Runnable {
private void testMethod() throws InterruptedException
{
try
{
System.out.println("In try block");
throw new NullPointerException();
}
catch(NullPointerException npe)
{
System.out.println("In catch block");
}
finally
{
System.out.println("In finally block");
}
}
@Override
protected void finalize() throws Throwable {
System.out.println("In finalize block");
super.finalize();
}
@Override
public void run() {
try {
testMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class TestMain
{
@SuppressWarnings("deprecation")
public static void main(String[] args) {
for(int i=1;i< =3;i++)
{
new Thread(new TryCatchFinallyTest()).start();
}
}
}
เอาท์พุต: ใน try block ใน catch block ในในที่สุด block ใน try block ใน catch block ในในที่สุดก็บล็อก ใน try block ใน catch block ในบล็อกสุดท้าย น่าประหลาดใจที่วิธีนี้finalize
ไม่ได้ดำเนินการกับเธรดใด ๆ นี่เป็นการพิสูจน์คำพูดของฉัน ฉันคิดว่าเหตุผลก็คือผู้เข้ารอบสุดท้ายจะดำเนินการโดยเธรดตัวรวบรวมขยะแยกต่างหาก หาก Java Virtual Machine หยุดทำงานเร็วเกินไป ตัวรวบรวมขยะจะไม่มีเวลาเพียงพอที่จะสร้างและดำเนินการตัวสรุปผล เหตุผลอื่นที่ไม่ใช้วิธีการนี้finalize()
อาจเป็น:
- วิธีการนี้
finalize()
ใช้ไม่ได้กับเชนเช่นคอนสตรัคเตอร์ ซึ่งหมายความว่าเมื่อคุณเรียกตัวสร้างคลาส ตัวสร้างคลาสระดับสูงจะถูกเรียกโดยไม่มีเงื่อนไข แต่ในกรณีของวิธีนี้finalize()
สิ่งนี้จะไม่เกิดขึ้นfinalize()
ต้องเรียกเมธอด ซูเปอร์คลาสอย่างชัดเจน - ข้อยกเว้นใดๆ ที่เกิดขึ้นโดยวิธีการนี้
finalize
จะถูกละเว้นโดยเธรดตัวรวบรวมขยะ และจะไม่ถูกเผยแพร่เพิ่มเติม ซึ่งหมายความว่าเหตุการณ์จะไม่ถูกบันทึกไว้ในบันทึกของคุณ นี่มันแย่มากเลยใช่ไหม? -
คุณยังได้รับค่าปรับด้านประสิทธิภาพอย่างมากหากมีวิธีการ
finalize()
ดังกล่าวในชั้นเรียนของคุณ ใน Effective Programming (ฉบับพิมพ์ครั้งที่ 2) Joshua Bloch กล่าวว่า:
“ใช่ และอีกอย่างหนึ่ง: มีการลงโทษด้านประสิทธิภาพอย่างมากเมื่อใช้โปรแกรมสรุปผล บนเครื่องของฉัน เวลาในการสร้างและทำลายวัตถุธรรมดาคือประมาณ 5.6 นาโนวินาที
การเพิ่มตัวปิดท้ายจะเพิ่มเวลาเป็น 2,400 นาโนวินาที กล่าวอีกนัยหนึ่ง การสร้างและลบออบเจ็กต์ด้วยโปรแกรมขั้นสุดท้ายจะช้าลงประมาณ 430 เท่า”
เหตุใดจึงไม่ควรใช้ HashMap ในสภาพแวดล้อมแบบมัลติเธรด สิ่งนี้อาจทำให้เกิดการวนซ้ำไม่สิ้นสุดหรือไม่?
เรารู้ว่าHashMap
นี่คือคอลเล็กชันที่ไม่ซิงโครไนซ์ ซึ่งคอลเลกชั่นที่ซิงโครไนซ์HashTable
คือ ดังนั้น เมื่อคุณเข้าถึงคอลเลกชันและในสภาพแวดล้อมแบบมัลติเธรดที่เธรดทั้งหมดสามารถเข้าถึงอินสแตนซ์เดียวของคอลเลกชันได้ จะปลอดภัยกว่าที่จะใช้HashTable
ด้วยเหตุผลที่ชัดเจน เช่น หลีกเลี่ยงการอ่านสกปรกและรับรองความสอดคล้องของข้อมูล ในกรณีที่เลวร้ายที่สุด สภาพแวดล้อมแบบมัลติเธรดนี้จะทำให้เกิดการวนซ้ำไม่สิ้นสุด ใช่มันเป็นความจริง. HashMap.get()
อาจทำให้เกิดการวนซ้ำไม่สิ้นสุด มาดูกันว่าเป็นอย่างไร? หากคุณดูที่ซอร์สโค้ดของวิธีการHashMap.get(Object key)
ดูเหมือนว่านี้:
public Object get(Object key) {
Object k = maskNull(key);
int hash = hash(k);
int i = indexFor(hash, table.length);
Entry e = table[i];
while (true) {
if (e == null)
return e;
if (e.hash == hash && eq(k, e.key))
return e.value;
e = e.next;
}
}
while(true)
สามารถตกเป็นเหยื่อของลูปไม่สิ้นสุดในสภาพแวดล้อมรันไทม์แบบมัลติเธรดได้เสมอ หากe.next
สามารถชี้ไปที่ตัวมันเองได้ ด้วยเหตุผลบางประการ สิ่งนี้จะทำให้เกิดการวนซ้ำไม่รู้จบ แต่e.next
จะชี้ไปที่ตัวมันเองได้อย่างไร (นั่นคือ ถึงe
)? สิ่งนี้สามารถเกิดขึ้นได้ในวิธีการvoid transfer(Entry[] newTable)
ที่เรียกว่าในขณะที่HashMap
กำลังปรับขนาด
do {
Entry next = e.next;
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
} while (e != null);
โค้ดชิ้นนี้มีแนวโน้มที่จะสร้างการวนซ้ำไม่สิ้นสุดหากการปรับขนาดเกิดขึ้นในเวลาเดียวกันกับที่เธรดอื่นพยายามเปลี่ยนอินสแตนซ์แมป ( HashMap
) วิธีเดียวที่จะหลีกเลี่ยงสถานการณ์นี้คือการใช้การซิงโครไนซ์ในโค้ดของคุณ หรือดีกว่านั้น ให้ใช้คอลเลกชันที่ซิงโครไนซ์
อธิบายนามธรรมและการห่อหุ้ม พวกเขาเชื่อมโยงกันอย่างไร?
พูดง่ายๆ ก็คือ “ สิ่งที่เป็นนามธรรมจะแสดงเฉพาะคุณสมบัติของวัตถุที่มีนัยสำคัญสำหรับมุมมองปัจจุบัน ” ในทฤษฎีการเขียนโปรแกรมเชิงวัตถุ นามธรรมเกี่ยวข้องกับความสามารถในการกำหนดวัตถุที่เป็นตัวแทนของ "ผู้แสดง" ที่เป็นนามธรรมซึ่งสามารถทำงาน เปลี่ยนแปลงและรายงานการเปลี่ยนแปลงในสถานะของพวกเขา และ "โต้ตอบ" กับวัตถุอื่น ๆ ในระบบ นามธรรมในภาษาโปรแกรมใดๆ ก็ตามทำงานได้หลายวิธี ดังจะเห็นได้จากการสร้างรูทีนเพื่อกำหนดอินเทอร์เฟซสำหรับคำสั่งภาษาระดับต่ำ นามธรรมบางอย่างพยายามจำกัดความกว้างของการนำเสนอความต้องการของโปรแกรมเมอร์โดยรวมโดยการซ่อนนามธรรมที่ถูกสร้างขึ้น เช่น รูปแบบการออกแบบ โดยทั่วไปแล้ว นามธรรมสามารถเห็นได้สองวิธี: Data abstractionเป็นวิธีการสร้างประเภทข้อมูลที่ซับซ้อนและเปิดเผยเฉพาะการดำเนินการที่มีความหมายเท่านั้นเพื่อโต้ตอบกับโมเดลข้อมูล ในขณะเดียวกันก็ซ่อนรายละเอียดการใช้งานทั้งหมดจากโลกภายนอก การดำเนินการที่เป็นนามธรรมเป็นกระบวนการในการระบุข้อความที่สำคัญทั้งหมดและเปิดเผยเป็นหน่วยงาน เรามักจะใช้คุณสมบัตินี้เมื่อเราสร้างวิธีการทำงานบางอย่าง การจำกัดข้อมูลและวิธีการภายในคลาสร่วมกับการซ่อน (โดยใช้การควบคุมการเข้าถึง) มักเรียกว่าการห่อหุ้ม ผลลัพธ์ที่ได้คือชนิดข้อมูลที่มีลักษณะและพฤติกรรม การห่อหุ้มโดยพื้นฐานแล้วยังเกี่ยวข้องกับการซ่อนข้อมูลและการซ่อนการใช้งาน “สรุปทุกสิ่งที่เปลี่ยนแปลงได้” . คำพูดนี้เป็นหลักการออกแบบที่รู้จักกันดี สำหรับเรื่องนั้น ในคลาสใดก็ตาม การเปลี่ยนแปลงข้อมูลสามารถเกิดขึ้นได้ที่รันไทม์ และการเปลี่ยนแปลงการใช้งานสามารถเกิดขึ้นได้ในเวอร์ชันต่อๆ ไป ดังนั้นการห่อหุ้มจึงใช้ได้กับทั้งข้อมูลและการนำไปใช้งาน จึงสามารถเชื่อมต่อได้ดังนี้:- สิ่งที่เป็นนามธรรมส่วนใหญ่เป็นสิ่งที่ชั้นเรียนสามารถทำได้ [ไอเดีย]
- การห่อหุ้มมีมากกว่าวิธีการใช้งานฟังก์ชันนี้ให้สำเร็จ [การใช้งาน]
ความแตกต่างระหว่างอินเทอร์เฟซและคลาสนามธรรม?
ความแตกต่างหลักสามารถแสดงได้ดังนี้:- อินเทอร์เฟซไม่สามารถใช้วิธีการใด ๆ ได้ แต่คลาสนามธรรมสามารถทำได้
- คลาสสามารถใช้อินเทอร์เฟซได้หลายแบบ แต่สามารถมีซูเปอร์คลาสได้เพียงคลาสเดียวเท่านั้น (นามธรรมหรือไม่ใช่นามธรรม)
- อินเทอร์เฟซไม่ได้เป็นส่วนหนึ่งของลำดับชั้นของคลาส คลาสที่ไม่เกี่ยวข้องสามารถใช้อินเทอร์เฟซเดียวกันได้
Cat
และDog
สามารถสืบทอดมาจากคลาสนามธรรมAnimal
และคลาสฐานนามธรรมนี้จะใช้วิธีvoid Breathe()
การหายใจ ซึ่งสัตว์ทุกตัวจะดำเนินการในลักษณะเดียวกัน คำกริยาใดบ้างที่สามารถนำไปใช้กับชั้นเรียนของฉันและนำไปใช้กับผู้อื่นได้ สร้างอินเทอร์เฟซสำหรับคำกริยาแต่ละคำเหล่านี้ ตัวอย่างเช่น สัตว์ทุกตัวสามารถกินได้ ดังนั้นฉันจะสร้างอินเทอร์เฟซIFeedable
และทำให้มันAnimal
ใช้อินเทอร์เฟซนั้น ดีพอที่จะใช้อินเทอร์เฟซเท่านั้นDog
( สามารถชอบฉันได้) แต่ไม่ใช่ทั้งหมด มีคนกล่าวว่า: ความแตกต่างที่สำคัญคือจุดที่คุณต้องการนำไปปฏิบัติ เมื่อคุณสร้างอินเทอร์เฟซ คุณสามารถย้ายการใช้งานไปยังคลาสใดๆ ที่ใช้อินเทอร์เฟซของคุณได้ ด้วยการสร้างคลาสนามธรรม คุณสามารถแบ่งปันการใช้งานคลาสที่ได้รับทั้งหมดในที่เดียว และหลีกเลี่ยงสิ่งเลวร้ายมากมาย เช่น รหัสที่ซ้ำกัน Horse
ILikeable
StringBuffer ช่วยประหยัดหน่วยความจำได้อย่างไร
คลาสString
ถูกนำไปใช้เป็นอ็อบเจ็กต์ที่ไม่เปลี่ยนรูป ซึ่งหมายความว่าเมื่อคุณเริ่มตัดสินใจที่จะใส่บางสิ่งลงในอ็อบเจ็กต์String
เครื่องเสมือนจะจัดสรรอาเรย์ที่มีความยาวคงที่เท่ากับขนาดของค่าดั้งเดิมของคุณทุกประการ จากนั้นจะถือเป็นค่าคงที่ภายในเครื่องเสมือน ซึ่งจะช่วยปรับปรุงประสิทธิภาพที่สำคัญหากค่าของสตริงไม่เปลี่ยนแปลง อย่างไรก็ตาม หากคุณตัดสินใจที่จะเปลี่ยนเนื้อหาของสตริงในทางใดทางหนึ่ง สิ่งที่เครื่องเสมือนทำจริงๆ คือการคัดลอกเนื้อหาของสตริงต้นฉบับลงในพื้นที่ชั่วคราว ทำการเปลี่ยนแปลง จากนั้นบันทึกการเปลี่ยนแปลงเหล่านั้นไปยังอาร์เรย์หน่วยความจำใหม่ ดังนั้นการเปลี่ยนแปลงค่าของสตริงหลังจากการกำหนดค่าเริ่มต้นจึงเป็นการดำเนินการที่มีราคาแพง StringBuffer
ในทางกลับกัน ถูกนำมาใช้เป็นอาร์เรย์ขยายแบบไดนามิกภายในเครื่องเสมือน ซึ่งหมายความว่าการดำเนินการแก้ไขใดๆ สามารถเกิดขึ้นได้บนเซลล์หน่วยความจำที่มีอยู่ และหน่วยความจำใหม่จะได้รับการจัดสรรตามความจำเป็น อย่างไรก็ตาม ไม่มีวิธีใดที่เครื่องเสมือนจะทำการออปติไมซ์ได้StringBuffer
เนื่องจากเนื้อหาในเครื่องถือว่าไม่สอดคล้องกันในแต่ละอินสแตนซ์
เหตุใดจึงมีการประกาศวิธีการรอและแจ้งเตือนในคลาส Object แทนที่จะเป็น Thread
วิธีการ,wait
จำเป็นเฉพาะเมื่อคุณต้องการให้เธรดของคุณมีสิทธิ์เข้าถึงทรัพยากรที่ใช้ร่วมกัน และทรัพยากรที่ใช้ร่วมกันอาจเป็นวัตถุ Java ใดๆ ในฮีป ดังนั้น วิธีการเหล่านี้จึงถูกกำหนดไว้บนคลาสพื้นฐานเพื่อให้แต่ละวัตถุมีตัวควบคุมที่อนุญาตให้เธรดรอบนจอภาพ Java ไม่มีวัตถุพิเศษใด ๆ ที่ใช้ในการแบ่งปันทรัพยากรที่ใช้ร่วมกัน ไม่มีการกำหนดโครงสร้างข้อมูลดังกล่าว ดังนั้นจึงเป็นความรับผิดชอบของชั้นเรียน ที่ จะกลายเป็นทรัพยากรที่ใช้ร่วมกัน และจัดเตรียมวิธีการช่วยเหลือ เช่น, , Java มีพื้นฐานมาจากแนวคิดเรื่องจอภาพของ Charles Hoare ใน Java วัตถุทั้งหมดมีจอภาพ เธรดรออยู่บนมอนิเตอร์ ดังนั้นเพื่อดำเนินการรอ เราจำเป็นต้องมีพารามิเตอร์สองตัว: notify
notifyAll
Object
Object
wait()
notify()
notifyAll()
- ด้าย
- มอนิเตอร์ (วัตถุใด ๆ )
wait
) นี่เป็นการออกแบบที่ดี เพราะหากเราสามารถบังคับให้เธรดอื่นรอบนจอภาพเฉพาะได้ มันจะส่งผลให้เกิด "การบุกรุก" ทำให้การออกแบบ/การเขียนโปรแกรมโปรแกรมแบบขนานทำได้ยาก โปรดจำไว้ว่าใน Java การดำเนินการทั้งหมดที่รบกวนเธรดอื่นจะเลิกใช้แล้ว (เช่นstop()
)
เขียนโปรแกรมเพื่อสร้าง deadlock ใน Java แล้วแก้ไข
ใน Javadeadlock
นี่เป็นสถานการณ์ที่อย่างน้อยสองเธรดเก็บบล็อกไว้บนรีซอร์สที่แตกต่างกัน และทั้งสองกำลังรอให้รีซอร์สอื่นพร้อมใช้งานเพื่อทำงานให้เสร็จสิ้น และไม่มีใครสามารถออกจากการล็อคทรัพยากรที่กำลังถืออยู่ได้ 
package thread;
public class ResolveDeadLockTest {
public static void main(String[] args) {
ResolveDeadLockTest test = new ResolveDeadLockTest();
final A a = test.new A();
final B b = test.new B();
// Thread-1
Runnable block1 = new Runnable() {
public void run() {
synchronized (a) {
try {
// Добавляем задержку, чтобы обе нити могли начать попытки
// блокирования ресурсов
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Thread-1 заняла A но также нуждается в B
synchronized (b) {
System.out.println("In block 1");
}
}
}
};
// Thread-2
Runnable block2 = new Runnable() {
public void run() {
synchronized (b) {
// Thread-2 заняла B но также нуждается в A
synchronized (a) {
System.out.println("In block 2");
}
}
}
};
new Thread(block1).start();
new Thread(block2).start();
}
// Resource A
private class A {
private int i = 10;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
}
// Resource B
private class B {
private int i = 20;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
}
}
การเรียกใช้โค้ดด้านบนจะส่งผลให้เกิดการหยุดชะงักด้วยเหตุผลที่ชัดเจนมาก (อธิบายไว้ข้างต้น) ตอนนี้เราจำเป็นต้องแก้ไขปัญหานี้ ฉันเชื่อว่าการแก้ปัญหาใดๆ อยู่ที่ต้นตอของปัญหานั่นเอง ในกรณีของเรา รูปแบบการเข้าถึง A และ B คือปัญหาหลัก ดังนั้น เพื่อแก้ปัญหานี้ เราเพียงแค่เปลี่ยนลำดับของผู้ดำเนินการเข้าถึงเป็นทรัพยากรที่ใช้ร่วมกัน หลังจากการเปลี่ยนแปลงจะมีลักษณะดังนี้:
// Thread-1
Runnable block1 = new Runnable() {
public void run() {
synchronized (b) {
try {
// Добавляем задержку, чтобы обе нити могли начать попытки
// блокирования ресурсов
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Thread-1 заняла B но также нуждается в А
synchronized (a) {
System.out.println("In block 1");
}
}
}
};
// Thread-2
Runnable block2 = new Runnable() {
public void run() {
synchronized (b) {
// Thread-2 заняла B но также нуждается в А
synchronized (a) {
System.out.println("In block 2");
}
}
}
};
เรียกใช้คลาสนี้อีกครั้ง และตอนนี้คุณจะไม่เห็นการหยุดชะงัก ฉันหวังว่านี่จะช่วยคุณหลีกเลี่ยงการหยุดชะงักและกำจัดมันออกไปหากคุณพบมัน
จะเกิดอะไรขึ้นหากคลาสของคุณที่ใช้อินเทอร์เฟซแบบซีเรียลไลซ์มีส่วนประกอบที่ไม่สามารถซีเรียลไลซ์ได้ จะแก้ไขปัญหานี้ได้อย่างไร?
ในกรณีนี้ มันจะถูกโยนทิ้งNotSerializableException
ระหว่างการดำเนินการ เพื่อแก้ไขปัญหานี้ มีวิธีแก้ไขที่ง่ายมาก - ทำเครื่องหมายที่ช่องเหล่าtransient
นี้ ซึ่งหมายความว่าฟิลด์ที่เลือกจะไม่ถูกทำให้เป็นอนุกรม หากคุณต้องการจัดเก็บสถานะของฟิลด์เหล่านี้ด้วย คุณต้องพิจารณาตัวแปรอ้างอิงซึ่งมีการใช้งานSerializable
. คุณอาจจำเป็นต้องใช้readResolve()
และwriteResolve()
วิธี การ สรุป:
- ขั้นแรก ทำให้ฟิลด์ของคุณไม่สามารถซีเรียลไลซ์
transient
ได้ - ขั้นแรก
writeObject
ให้เรียกใช้defaultWriteObject
เธรดเพื่อบันทึกฟิลด์ที่ไม่ใช่transient
ฟิลด์ทั้งหมด จากนั้นเรียกใช้เมธอดที่เหลือเพื่อทำให้เป็นอนุกรมคุณสมบัติแต่ละรายการของอ็อบเจ็กต์ที่ไม่ทำให้เป็นอนุกรมของคุณ - ใน
readObject
ขั้นแรกให้เรียกdefaultReadObject
ใช้สตรีมเพื่ออ่านฟิลด์ที่ไม่ใช่ทั้งหมดtransient
จากนั้นเรียกวิธีการอื่น (ซึ่งสอดคล้องกับวิธีที่คุณเพิ่มในwriteObject
) เพื่อทำการดีซีเรียลไลซ์ที่ไม่ใช่transient
อ็อบเจ็กต์ ของคุณ
อธิบายคำสำคัญชั่วคราวและผันผวนใน Java
"คำสำคัญtransient
ถูกใช้เพื่อระบุฟิลด์ที่จะไม่ถูกทำให้เป็นอนุกรม" ตามข้อกำหนดภาษา Java: ตัวแปรสามารถทำเครื่องหมายด้วยตัวบ่งชี้ชั่วคราวเพื่อระบุว่าไม่ได้เป็นส่วนหนึ่งของสถานะคงอยู่ของวัตถุ ตัวอย่างเช่น คุณอาจมีช่องที่ได้มาจากช่องอื่น และขอแนะนำให้รับช่องเหล่านั้นโดยทางโปรแกรม แทนที่จะกู้คืนสถานะผ่านการทำให้เป็นอนุกรม ตัวอย่างเช่น ในคลาส ฟิลด์BankPayment.java
ต่างๆ เช่นprincipal
(ผู้อำนวยการ) และrate
(อัตรา) สามารถซีเรียลไลซ์ได้ และinterest
(ดอกเบี้ยค้างรับ) สามารถคำนวณได้ตลอดเวลา แม้หลังจากการดีซีเรียลไลซ์แล้วก็ตาม หากเราจำได้ว่า แต่ละเธรดใน Java มีหน่วยความจำในเครื่องของตัวเอง และดำเนินการอ่าน/เขียนในหน่วยความจำในเครื่องนี้ เมื่อการดำเนินการทั้งหมดเสร็จสิ้น ระบบจะเขียนสถานะที่แก้ไขของตัวแปรลงในหน่วยความจำที่ใช้ร่วมกัน ซึ่งเป็นจุดที่เธรดทั้งหมดเข้าถึงตัวแปร โดยทั่วไป นี่เป็นเธรดปกติภายในเครื่องเสมือน แต่ตัวดัดแปลงระเหยจะบอกเครื่องเสมือนว่าการเข้าถึงของเธรดไปยังตัวแปรนั้นจะต้องตรงกับสำเนาของตัวแปรนั้นกับสำเนาหลักของตัวแปรในหน่วยความจำเสมอ ซึ่งหมายความว่าทุกครั้งที่เธรดต้องการอ่านสถานะของตัวแปร เธรดนั้นจะต้องล้างสถานะหน่วยความจำภายในและอัปเดตตัวแปรจากหน่วยความจำหลัก Volatile
มีประโยชน์มากที่สุดในอัลกอริธึมที่ไม่มีการล็อค คุณทำเครื่องหมายตัวแปรที่จัดเก็บข้อมูลที่ใช้ร่วมกันว่ามีความผันผวน จากนั้นคุณจะไม่ใช้การล็อกเพื่อเข้าถึงตัวแปรนั้น และการเปลี่ยนแปลงทั้งหมดที่ทำโดยเธรดหนึ่งจะมองเห็นได้โดยผู้อื่น หรือหากคุณต้องการสร้างความสัมพันธ์ "ที่เกิดขึ้นภายหลัง" เพื่อให้แน่ใจว่าการคำนวณจะไม่เกิดซ้ำ อีกครั้งเพื่อให้แน่ใจว่าการเปลี่ยนแปลงจะมองเห็นได้แบบเรียลไทม์ ควรใช้สารระเหยเพื่อเผยแพร่อ็อบเจ็กต์ที่ไม่เปลี่ยนรูปได้อย่างปลอดภัยในสภาพแวดล้อมแบบมัลติเธรด การประกาศภาคสนามpublic volatile ImmutableObject
ช่วยให้แน่ใจว่าเธรดทั้งหมดเห็นการอ้างอิงอินสแตนซ์ที่มีอยู่ในปัจจุบันเสมอ
ความแตกต่างระหว่างตัววนซ้ำและ ListIterator?
เราสามารถใช้หรือเพื่อIterator
วนซ้ำองค์ประกอบต่างๆ แต่สามารถใช้เพื่อวนซ้ำองค์ประกอบเท่านั้น ความแตกต่างอื่นๆ มีอธิบายไว้ด้านล่าง คุณสามารถ: Set
List
Map
ListIterator
List
- วนซ้ำในลำดับย้อนกลับ
- รับดัชนีได้ทุกที่
- เพิ่มมูลค่าได้ทุกที่
- ตั้งค่าใด ๆ ที่ตำแหน่งปัจจุบัน
GO TO FULL VERSION