วิธีคงที่ไม่ซิงโครไนซ์เธรดปลอดภัยหรือไม่ถ้าพวกเขาไม่แก้ไขตัวแปรคลาสคงที่


145

ฉันสงสัยว่าคุณมีวิธีการคงที่ที่ไม่ได้ทำข้อมูลให้ตรงกัน แต่ไม่ได้แก้ไขตัวแปรคงที่ใด ๆ มันเป็นเธรดที่ปลอดภัยหรือไม่ จะเกิดอะไรขึ้นถ้าเมธอดสร้างตัวแปรโลคอลภายในมัน? ตัวอย่างเช่นรหัสต่อไปนี้ปลอดภัยไหม?

public static String[] makeStringArray( String a, String b ){
    return new String[]{ a, b };
}

ดังนั้นถ้าฉันมีสองเธรดเรียกวิธีการอย่างต่อเนื่องและพร้อมกันหนึ่งกับสุนัข (พูดว่า "Great dane" และ "bull dog") และอื่น ๆ ที่มีแมว (พูดว่า "เปอร์เซีย" และ "สยาม") ฉันจะเคยได้รับแมวและสุนัข อยู่ในอาร์เรย์เดียวกันหรือไม่ หรือแมวและสุนัขจะไม่อยู่ในกระบวนการเดียวกันในเวลาเดียวกันหรือไม่?


หัวข้ออื่นเกี่ยวกับปัญหานี้: stackoverflow.com/questions/8015797/…
象嘉道

2
นั่นเป็นคำถามที่แตกต่างกันนี่คือว่าการเรียกใช้เมธอดแบบสแตติกนั้นปลอดภัยต่อเธรดหรือไม่
เลื่อน

คำตอบ:


212

วิธีนี้ปลอดภัยกับเธรด 100% แม้ว่าจะไม่ได้ใช้staticก็ตาม ปัญหาเกี่ยวกับความปลอดภัยของเธรดเกิดขึ้นเมื่อคุณต้องการใช้ข้อมูลร่วมกันระหว่างเธรด - คุณต้องดูแล atomicity การมองเห็น ฯลฯ

วิธีการนี้จะทำงานกับพารามิเตอร์ที่อยู่ในสแต็กและการอ้างอิงถึงวัตถุที่ไม่เปลี่ยนรูปในกอง สแต็กเป็นแบบโลคัลกับเธรดดังนั้นจึงไม่มีการแชร์ข้อมูลเกิดขึ้น

วัตถุที่ไม่เปลี่ยนรูป ( Stringในกรณีนี้) ก็เป็นแบบ thread-safe เนื่องจากเมื่อสร้างแล้วจะไม่สามารถเปลี่ยนแปลงได้และเธรดทั้งหมดจะเห็นค่าเดียวกัน ในทางตรงกันข้ามหากวิธีการที่ได้รับการยอมรับ (ไม่แน่นอน) Dateคุณอาจจะมีปัญหา สองเธรดสามารถปรับเปลี่ยนอินสแตนซ์ของวัตถุเดียวกันได้พร้อมกันซึ่งก่อให้เกิดสภาพการแข่งขันและปัญหาการมองเห็น


4
คำตอบที่ถูกต้อง ตัวแปรระดับวิธีการจำลองแบบในแต่ละกองซ้อนการดำเนินการเธรด
Sid

ในทางเทคนิควิธีการที่จะ inline และพารามิเตอร์จะลงทะเบียน CPU อย่างไรก็ตามคำตอบนั้นถูกต้อง
bestsss

43
สแต็คนั้นแน่นอนว่าอยู่ในท้องถิ่นกับเธรดปัจจุบัน แต่คุณสามารถอ้างอิงไปยังวัตถุที่แชร์ในสแต็กนั้นได้ นี่ไม่ใช่ปัญหาในตัวอย่างเนื่องจากสตริงไม่เปลี่ยนรูป แต่วิธีการที่ปรับเปลี่ยนพารามิเตอร์ที่ส่งผ่านอาจมีปัญหาด้านความปลอดภัยของเธรดถ้าวัตถุที่ส่งผ่านนี้สามารถเข้าถึงได้จากหลายเธรด
Jörn Horstmann

1
ดังที่ @TomaszNurkiewicz พูดถึงถ้าเราผ่านการอ้างอิงวัตถุที่ไม่แน่นอนเราสามารถเข้าสู่สภาวะการแข่งขัน สิ่งนี้จะเป็นจริงหรือไม่แม้ว่าวิธีการจะไม่เปลี่ยนแปลงวัตถุ แต่อย่างใด ฉันหมายความว่ามันจะยังคงถูกจัดประเภทเป็นเงื่อนไขการแข่งขันเนื่องจากวัตถุไม่แน่นอนหรือไม่ แล้วถ้าเราเพิ่มคำค้นหาสุดท้ายลงในพารามิเตอร์ล่ะ?
Rafay

ถ้าฉันส่งคลาสอ็อบเจ็กต์ในเมธอด? varaible ในกองหรือกองจะได้หรือไม่
grep

28

เมธอดสามารถเป็นเธรดที่ไม่ปลอดภัยเมื่อเปลี่ยนสถานะที่แบ่งใช้บางสถานะเท่านั้น ไม่ว่าจะเป็นแบบคงที่หรือไม่เกี่ยวข้อง


3
@Konrad_Garus คำถามที่นี่เป็นไปตามเส้นของตัวแปรท้องถิ่นที่ประกอบด้วยรัฐที่ใช้ร่วมกันหรือไม่หรือว่าสแต็คสำหรับวิธีการคงที่เป็นต่อกระทู้หรือใช้ร่วมกัน
เลื่อน

"เมธอดอาจไม่ปลอดภัยเมื่อเปลี่ยนสถานะที่ใช้ร่วมกันบางอย่างเท่านั้น" ไม่มันสามารถเป็นเธรดที่ไม่ปลอดภัยได้หากเข้าถึงสถานะที่ใช้ร่วมกันโดยไม่เปลี่ยนแปลง การเข้าถึงวัตถุที่ไม่แน่นอนที่ไม่ซิงโครไนซ์สามารถเข้าถึงสถานะที่ไม่สอดคล้องกันหากวัตถุนั้นถูกเปลี่ยนแปลงโดยเธรดอื่นแม้ว่าเธรดอื่นจะซิงโครไนซ์อย่างเหมาะสม เธรดทั้งสองต้องการการซิงโครไนซ์ที่เหมาะสมเพื่อความปลอดภัยของเธรด
Warren Dew

12

ฟังก์ชั่นนี้เป็นเกลียวที่ปลอดภัยอย่างสมบูรณ์

ถ้าคุณคิดเกี่ยวกับมัน ... สมมติว่าจะเกิดอะไรขึ้นถ้าสิ่งนี้ต่างออกไป ทุกฟังก์ชั่นปกติจะมีปัญหาเธรดถ้าไม่ซิงโครไนซ์ดังนั้นฟังก์ชัน API ทั้งหมดใน JDK จะต้องซิงโครไนซ์เพราะอาจถูกเรียกโดยเธรดหลาย ๆ ตัว และเนื่องจากส่วนใหญ่แอพใช้ API บางตัวแอพแบบมัลติเธรดจะเป็นไปไม่ได้อย่างมีประสิทธิภาพ

มันไร้สาระเกินกว่าที่จะคิดเกี่ยวกับมันดังนั้นสำหรับคุณเท่านั้น: วิธีการนั้นไม่ได้มีความปลอดภัยถ้ามีเหตุผลที่ชัดเจนว่าทำไมอาจมีปัญหา ลองคิดดูเสมอว่าถ้ามีหลายเธรดในฟังก์ชั่นของฉันและจะทำอย่างไรถ้าคุณมี step-debugger และจะก้าวไปอีกขั้นหนึ่งหลังจากก้าวแรก ... จากนั้นเธรดที่สอง ... อาจเป็นครั้งที่สองอีกครั้ง ... จะมีปัญหาไหม? หากคุณพบหนึ่งมันไม่ปลอดภัยกระทู้

โปรดทราบว่าคลาส Java 1.5 Collection ส่วนใหญ่ไม่ได้เป็น threadsafe ยกเว้นที่ระบุไว้เช่น ConcurrentHashMap

และถ้าคุณต้องการที่จะดำน้ำในสิ่งนี้จริงๆให้ดูคำสำคัญที่ระเหยได้และผลข้างเคียงทั้งหมด ดูที่คลาสเซมาฟอร์ () และล็อค () และเพื่อน ๆ ของพวกเขาใน java.util.Concurrent อ่านเอกสาร API ทั้งหมดรอบ ๆ คลาส มันก็คุ้มค่าที่จะเรียนรู้และสร้างความพึงพอใจเช่นกัน

ขออภัยสำหรับคำตอบที่ซับซ้อนเกินไป


2
"ถ้าคุณคิดเกี่ยวกับมัน ... สมมติว่าจะเกิดอะไรขึ้นถ้าสิ่งนี้แตกต่างกันทุกฟังก์ชั่นปกติจะมีปัญหาเธรดถ้าไม่ซิงโครไนซ์ดังนั้นฟังก์ชั่น API ทั้งหมดใน JDK จะต้องซิงโครไนซ์ หัวข้อ." จุดดี!
เลื่อน

1

ใช้staticคำหลักที่มีวิธีการคงที่ตรงกันเพื่อแก้ไขข้อมูลคงที่ที่ใช้ร่วมกันระหว่างกระทู้ กับstaticคำหลักกระทู้ทั้งหมดที่สร้างขึ้นจะต่อสู้กับวิธีการรุ่นเดียว

ใช้volatileคำหลักพร้อมกับวิธีการอินสแตนซ์ที่ซิงโครไนซ์จะรับประกันว่าแต่ละเธรดมีสำเนาของข้อมูลที่แชร์และไม่มีการอ่าน / เขียนจะรั่วไหลระหว่างเธรด


0

วัตถุสตริงที่ไม่เปลี่ยนรูปเป็นอีกเหตุผลหนึ่งสำหรับสถานการณ์ที่ปลอดภัยของเธรดข้างต้น แต่ถ้าใช้วัตถุที่ไม่แน่นอน (พูด makeMutableArray .. ) แน่นอนความปลอดภัยของเธรดจะแตก


คำถามคือถ้าการเรียกใช้วิธีการคงที่จะเคยเห็นข้อโต้แย้งของการโทรไปยังวิธีการเดียวกันจากหัวข้ออื่น คำตอบคือ "ไม่!" ดังก้อง ฉันรู้ แต่ต้องการพิสูจน์ให้เห็นถึงผู้ร่วมงานที่น่าสงสัย
เลื่อน

ทำไมคำตอบนี้จึงถูกโหวตลดลง? ประเด็นที่ไม่ได้มีส่วนร่วมจากคำตอบอื่นคือความไม่แน่นอนอาจอยู่ในขอบเขตหรือไม่อยู่ในขอบเขต ถ้าคุณส่งคืนค่าที่ไม่แน่นอน คำถามไม่ได้ตั้งคำถามอย่างแคบ ๆ ตามความคิดเห็น คำถามเพิ่มเติมหลังจากตัวอย่างรหัสสามารถแสดงเป็นรหัสได้หรืออาจเป็นการทดสอบหน่วย แต่ฉันเห็นอกเห็นใจด้วยการพยายามโน้มน้าวให้เพื่อนร่วมงาน "พวกเขาไม่เชื่อฉันหรือรหัสทดสอบของฉันหรือ Josh Bloch แต่พวกเขาอาจจะยอมรับคำตอบของ SO"
som-snytt
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.