ในโปรแกรมที่เกิดขึ้นพร้อมกัน โปรแกรมเมอร์จะให้ความสนใจเป็นพิเศษกับการซิงโครไนซ์ข้อมูลระหว่างกระบวนการหรือเธรดที่แตกต่างกัน โดยเฉพาะอย่างยิ่งเมื่อหลายเธรดแก้ไขตัวแปรเดียวกันในเวลาเดียวกัน จะต้องดำเนินการซิงโครไนซ์ที่เชื่อถือได้หรือมาตรการอื่น ๆ เพื่อให้แน่ใจว่าข้อมูลได้รับการแก้ไขอย่างถูกต้อง ประเด็นคือ หลักการคือ: อย่าถือว่าลำดับในการดำเนินการคำสั่ง คุณไม่สามารถคาดเดาลำดับที่คำสั่งระหว่างเธรดต่างๆ จะถูกดำเนินการได้
แต่ในโปรแกรมแบบเธรดเดียว มันมักจะง่ายสำหรับเราที่จะถือว่าคำสั่งนั้นถูกดำเนินการตามลำดับ ไม่เช่นนั้นเราจะจินตนาการได้ว่าการเปลี่ยนแปลงที่เลวร้ายจะเกิดขึ้นกับโปรแกรมอย่างไร โมเดลในอุดมคติคือ: ลำดับในการดำเนินการคำสั่งต่างๆ นั้นไม่ซ้ำกันและเรียงลำดับกัน ลำดับนี้เป็นลำดับที่เขียนไว้ในโค้ด โดยไม่คำนึงถึงโปรเซสเซอร์หรือปัจจัยอื่นๆ เป็นโมเดลที่ใช้ระบบฟอนนอยมันน์ แน่นอนว่าสมมติฐานนี้มีความสมเหตุสมผลในตัวเองและแทบจะไม่เกิดขึ้นอย่างผิดปกติในทางปฏิบัติ แต่ในความเป็นจริง ไม่มีสถาปัตยกรรมแบบมัลติโปรเซสเซอร์สมัยใหม่ใดที่นำโมเดลนี้มาใช้เพราะมันไม่มีประสิทธิภาพเกินไป ในการเพิ่มประสิทธิภาพการคอมไพล์และไปป์ไลน์ CPU เกือบทั้งหมดเกี่ยวข้องกับการเรียงลำดับคำสั่งใหม่
การเรียงลำดับเวลาใหม่
การเรียงลำดับเวลาคอมไพล์ใหม่โดยทั่วไปคือการปรับลำดับของคำสั่งเพื่อลดจำนวนการอ่านรีจิสเตอร์และจัดเก็บให้มากที่สุดโดยไม่ต้องเปลี่ยนซีแมนทิกส์ของโปรแกรม และเพื่อนำค่าที่เก็บไว้ของรีจิสเตอร์กลับมาใช้ใหม่อย่างเต็มที่
สมมติว่าคำสั่งแรกคำนวณค่าและกำหนดให้กับตัวแปร A และเก็บไว้ในรีจิสเตอร์ คำสั่งที่สองไม่เกี่ยวข้องกับ A แต่จำเป็นต้องครอบครองรีจิสเตอร์ (สมมติว่ามันจะครอบครองรีจิสเตอร์ที่มีตำแหน่ง A อยู่) คำสั่งใช้ค่าของ A และไม่เกี่ยวข้องกับคำสั่งที่สอง จากนั้น ถ้าตามโมเดลความสอดคล้องตามลำดับ A จะถูกใส่ลงในรีจิสเตอร์หลังจากดำเนินการคำสั่งแรกแล้ว A จะไม่มีอีกต่อไปเมื่อดำเนินการคำสั่งที่สอง และ A จะถูกอ่านเข้าสู่รีจิสเตอร์อีกครั้งเมื่อคำสั่งที่สามถูกดำเนินการ และในระหว่าง กระบวนการนี้ค่าของ A ไม่มีการเปลี่ยนแปลง โดยปกติคอมไพลเลอร์จะสลับตำแหน่งของคำสั่งที่สองและสาม เพื่อให้ A มีอยู่ในรีจิสเตอร์ที่ส่วนท้ายของคำสั่งแรก จากนั้นจึงสามารถอ่านค่าของ A ได้โดยตรงจากรีจิสเตอร์ ซึ่งช่วยลดค่าใช้จ่ายในการอ่านซ้ำ
ความสำคัญของการเรียงลำดับท่อใหม่
CPU สมัยใหม่เกือบทั้งหมดใช้กลไกไปป์ไลน์เพื่อเร่งการประมวลผลคำสั่ง โดยทั่วไป คำสั่งต้องใช้รอบสัญญาณนาฬิกาของ CPU หลายรอบในการประมวลผล และด้วยการดำเนินการแบบขนานของไปป์ไลน์ คำสั่งต่างๆ จึงสามารถดำเนินการได้ในรอบสัญญาณนาฬิกาเดียวกัน วิธีการระบุไว้ง่ายๆ เพียงแบ่งคำแนะนำออกเป็นอย่างอื่น รอบการดำเนินการ เช่น การอ่าน การกำหนดแอดเดรส การแยกวิเคราะห์ การดำเนินการ และขั้นตอนอื่นๆ จะได้รับการประมวลผลในส่วนประกอบที่แตกต่างกัน ในเวลาเดียวกัน ในหน่วยการดำเนินการ EU หน่วยการทำงานจะแบ่งออกเป็นส่วนประกอบต่างๆ เช่น ส่วนประกอบการบวก ส่วนประกอบการคูณ และการโหลดส่วนประกอบ องค์ประกอบการจัดเก็บข้อมูล ฯลฯ สามารถรับรู้การดำเนินการคำนวณต่างๆ แบบขนานเพิ่มเติมได้
สถาปัตยกรรมไปป์ไลน์กำหนดว่าคำสั่งควรดำเนินการแบบขนาน ไม่ใช่ตามที่พิจารณาในโมเดลตามลำดับ การเรียงลำดับใหม่เอื้อต่อการใช้งานไปป์ไลน์อย่างเต็มที่ ดังนั้นจึงบรรลุผลซูเปอร์สเกลาร์
มั่นใจในความเป็นระเบียบเรียบร้อย
แม้ว่าคำสั่งไม่จำเป็นต้องดำเนินการตามลำดับที่เราเขียนไว้ แต่ก็ไม่ต้องสงสัยเลยว่าในสภาพแวดล้อมแบบเธรดเดียว ผลลัพธ์สุดท้ายของการดำเนินการคำสั่งควรจะสอดคล้องกับผลกระทบในการดำเนินการตามลำดับ มิฉะนั้นการปรับให้เหมาะสมนี้จะสูญเสียความสำคัญไป
โดยปกติแล้ว หลักการข้างต้นจะเป็นที่พอใจไม่ว่าการเรียงลำดับคำสั่งใหม่จะดำเนินการในเวลาคอมไพล์หรือรันไทม์ก็ตาม
การเรียงลำดับใหม่ในโมเดลหน่วยเก็บข้อมูล Java
ใน Java Memory Model (JMM) การเรียงลำดับใหม่เป็นส่วนที่สำคัญมาก โดยเฉพาะอย่างยิ่งในการเขียนโปรแกรมพร้อมกัน JMM รับประกันซีแมนทิกส์การดำเนินการตามลำดับผ่านกฎที่เกิดขึ้นก่อน หากคุณต้องการให้เธรดดำเนินการ B สังเกตผลลัพธ์ของการดำเนินการเธรด A ดังนั้น A และ B จะต้องเป็นไปตามหลักการที่เกิดขึ้นก่อน มิฉะนั้น JVM จะดำเนินการตามอำเภอใจ การเรียงลำดับเพื่อปรับปรุงประสิทธิภาพของโปรแกรม
คีย์เวิร์ด volatile ช่วยให้มั่นใจในการมองเห็นตัวแปรได้ เนื่องจากการดำเนินการกับ volatile ล้วนอยู่ใน Main Memory และ Main Memory ถูกใช้ร่วมกันโดยเธรดทั้งหมด ราคานี้คือประสิทธิภาพที่ลดลง และรีจิสเตอร์หรือแคชไม่สามารถใช้งานได้เนื่องจากไม่ใช่ Global ไม่สามารถรับประกันการมองเห็นได้และอาจเกิดการอ่านที่สกปรก
ฟังก์ชั่นอีกอย่างหนึ่งของความผันผวนคือการป้องกันการเรียงลำดับใหม่ภายในเครื่อง คำแนะนำการใช้งานตัวแปรระเหยจะไม่ถูกเรียงลำดับใหม่ เพราะหากเรียงลำดับใหม่ อาจเกิดปัญหาการมองเห็นขึ้น
ในแง่ของการรับประกันการมองเห็น การล็อค (รวมถึงการล็อคที่ชัดเจน การล็อควัตถุ) และการอ่านและการเขียนตัวแปรอะตอมมิกสามารถรับประกันการมองเห็นตัวแปรได้ อย่างไรก็ตาม วิธีการนำไปใช้งานจะแตกต่างกันเล็กน้อย ตัวอย่างเช่น การล็อคการซิงโครไนซ์ทำให้แน่ใจได้ว่าข้อมูลจะถูกอ่านซ้ำจากหน่วยความจำเพื่อรีเฟรชแคชเมื่อได้รับการล็อคแล้ว ข้อมูลจะถูกเขียนกลับไปยังหน่วยความจำเพื่อให้แน่ใจ ข้อมูลสามารถมองเห็นได้ ในขณะที่ตัวแปรผันผวนเพียงแค่อ่านและเขียนหน่วยความจำ