คุณจะฆ่า Thread ใน Java ได้อย่างไร


374

คุณจะฆ่า a java.lang.Threadใน Java ได้อย่างไร?


2
จนถึงตอนนี้คุณไม่สามารถฆ่าเธรดได้ เนื่องจาก
destroy

1
ฉันชอบคำตอบเกี่ยวExecutorStatusกับคำถามนี้: stackoverflow.com/questions/2275443/how-to-timeout-a-thread
Kirby

9
@ loungerdork "ฉันคิดว่า Java ควรใช้วิธีการหยุด / ทำลายอย่างปลอดภัยสำหรับเธรดที่ควบคุมไม่ได้ซึ่งคุณไม่สามารถควบคุมได้แม้จะมีข้อแม้ของการล็อกและการผิดพลาดอื่น ๆ " ดังนั้นคุณจึงต้องการหยุดเธรดที่ไม่ปลอดภัย ฉันคิดว่าคุณมีอยู่แล้ว
DJClayworth

4
มันน่าทึ่งว่าคำถามแบบไหนที่จะได้รับผู้โหวต 212 คนในปี 2009 นี่จะถูกทำลายทันทีในวันนี้
Jonathon Reinhart

7
@ JonathonReinhart: ทำไมถึงเป็นเช่นนั้น? ดูเหมือนว่าจะเป็นคำถามที่ถูกต้องแม้กระทั่งทุกวันนี้ บางทีคุณอาจไม่ทราบถึงความคับข้องใจที่เกิดขึ้นเมื่อคุณมีเธรดที่ควบคุมไม่ได้และสามารถใช้ฟังก์ชันที่เลิกใช้แล้วเพื่อจัดการกับสิ่งนี้
TFuto

คำตอบ:


189

ดูนี้ด้ายโดย Sun Thread.stop()เกี่ยวกับเหตุผลที่พวกเขาเลิก มันมีรายละเอียดเกี่ยวกับสาเหตุที่เป็นวิธีที่ไม่ดีและสิ่งที่ควรทำเพื่อหยุดเธรดโดยทั่วไปได้อย่างปลอดภัย

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


1
หากคุณตรวจสอบเธรดที่คุณขัดจังหวะ isAlive () มันจะส่งคืนคุณเป็นจริงและพวกเขาจะเพิ่มไปยัง ThreadGroup ปัจจุบันของคุณ [] คุณจะเห็นสิ่งนี้ได้โดยใช้ Thread.currentThread.getThreadGroup (). list (); มันจะพิมพ์เธรดทั้งหมดที่มีและคุณจะเห็นหลายอินสแตนซ์ของเธรดของคุณถ้าคุณทำซ้ำการไหลของคุณ
AZ_

3
ถ้าคุณอยู่บนพีซีแล้วมันไม่มีปัญหา แต่ถ้าคุณกำลังพัฒนาซอฟต์แวร์สำหรับมือถือ (android ที่ฉันมีประสบการณ์) แล้วคุณจะได้รับ OutOfMemoryError
AZ_

2
มันสามารถ / ควรจะสังเกตว่าเพื่อให้แน่ใจว่าการสื่อสารที่รวดเร็วของการร้องขอหยุดผ่านธงตัวแปรจะต้องมีความผันผวน (หรือการเข้าถึงตัวแปรจะต้องตรงกัน) ตามที่ระบุไว้ในคำแนะนำ
mtsz

2
ลิงก์นี้ถูกฆ่าตายในตอนนี้ ฉันสามารถค้นหาได้ที่ archive.org แม้ว่า: web.archive.org/web/20090202093154/http://java.sun.com/j2se/…
Jay Taylor

2
ผมใช้วิธีการจากgetConnection() java.sql.DriverManagerหากการเชื่อมต่อใช้เวลานานเกินไปฉันพยายามที่จะฆ่าเธรดที่เกี่ยวข้องโดยการโทรThread.interrupt()แต่มันจะไม่ส่งผลกระทบต่อเธรดเลย Thread.stop()ทำงานอย่างไรก็ตามแม้ว่าพยากรณ์บอกว่ามันไม่ควรทำงานหากinterrupt()ไม่ได้ ฉันสงสัยว่ามันทำงานได้อย่างไรและหลีกเลี่ยงการใช้วิธีที่เลิกใช้แล้ว
Danny Lo

129

โดยทั่วไปคุณไม่ ..

คุณขอให้มันขัดจังหวะสิ่งที่มันทำโดยใช้Thread.interrupt () (ลิงค์ javadoc)

คำอธิบายที่ดีว่าเพราะเหตุใดใน javadoc ที่นี่ (ลิงค์ java technote)


@Fredrik เกิดอะไรขึ้นกับบริบทของเธรดเมื่อinterrupt()เรียกเมธอด คำถามหลักเกี่ยวข้องกับการสร้างบันทึกสำหรับเธรดใหม่แต่ละชุด
ABcDexter

3
@ABcDexter จุดทั้งหมดคือการขัดจังหวะที่ไม่ขัดจังหวะอะไรมันแค่ส่งสัญญาณไปยังรหัสในเธรด (หรือรหัสที่ถูกเรียกโดยเธรด) ว่ามีคนถามว่าจะขัดจังหวะสิ่งที่มันทำ เธรดควรจะหยุดการประมวลผลและการส่งคืนอย่างดีเช่นเดียวกับที่ทำในสิ่งที่ควรทำ (และ ณ จุดนั้นบริบทเธรดอาจถูกยกเลิกด้วย) OTOH ถ้าคุณบังคับให้หยุดกระทู้คำถามของคุณจะดีมากและคำตอบไม่ได้กำหนด
Fredrik

64

ใน Java กระทู้ไม่ได้ฆ่าตาย แต่หยุดของด้ายที่จะทำในวิธีการสหกรณ์ เธรดถูกขอให้ยุติและจากนั้นเธรดสามารถปิดได้อย่างเรียบร้อย

บ่อยครั้งที่volatile booleanฟิลด์ถูกใช้ซึ่งเธรดจะตรวจสอบและยุติเป็นระยะเมื่อมีการตั้งค่าเป็นค่าที่สอดคล้องกัน

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

วิธีการบล็อกไลบรารีบางวิธีรองรับการหยุดชะงัก

ทุกเธรดมีสถานะบูลีนที่ถูกขัดจังหวะและคุณควรใช้มัน สามารถนำไปใช้ได้ดังนี้:

public void run() {
   try {
      while (!interrupted()) {
         // ...
      }
   } catch (InterruptedException consumed)
      /* Allow thread to exit */
   }
}

public void cancel() { interrupt(); }

รหัสที่มาดัดแปลงมาจากJava Concurrency ในการปฏิบัติ เนื่องจากcancel()วิธีนี้เป็นแบบสาธารณะคุณสามารถปล่อยให้เธรดอื่นเรียกใช้เมธอดนี้ตามที่คุณต้องการ


และจะทำอย่างไรถ้าคุณเรียกใช้รหัสที่ไม่น่าเชื่อถือในฐานะปลั๊กอินหรือสคริปต์ Java ได้ฝังตัว sandbox สำหรับรหัสที่ไม่น่าเชื่อถือ และกล่องทรายนั้นไม่มีประโยชน์มันช่วยให้ทำงานได้โดยไม่หยุดแรง ลองนึกภาพคุณกำลังเขียนเบราว์เซอร์บนจาวา ความสามารถในการฆ่าสคริปต์หน้าโดยไม่มีค่ามีค่า
ayvango

@ayvango จากนั้นคุณต้องเรียกใช้สคริปต์นั้นในแซนด์บ็อกซ์ของคุณเอง Java sandbox ปกป้องเครื่องจากแอพพลิเคชั่นไม่ใช่ส่วนหนึ่งของแอปพลิเคชันจากกันและกัน
David Schwartz

@DavidSchwartz คุณหมายถึงว่าฉันควรใช้แพลตฟอร์มอื่นแล้ว java?
ayvango

@ayvango คุณยังสามารถใช้ Java sandbox เพื่อป้องกันเครื่องจากแอปพลิเคชันของคุณ แต่ถ้าคุณต้องการปกป้องส่วนของแอปพลิเคชันของคุณจากส่วนอื่น ๆ ของแอปพลิเคชันของคุณคุณจะต้องเลือกเครื่องมือบางอย่างที่สามารถทำได้
David Schwartz

@DavidSchwartz ASFAIK ไม่สามารถใช้เครื่องมือดังกล่าวได้หากไม่รองรับในระดับแพลตฟอร์ม แต่แน่นอนว่างานสามารถแก้ไขได้ด้วยเอนจิ้นสคริปต์ที่ถูกตีความอย่างสมบูรณ์ มันสามารถนับการลดแบบที่ erlang ทำและทำสิ่งอื่น ๆ
ayvango

20

วิธีหนึ่งคือการตั้งค่าตัวแปรคลาสและใช้เป็น Sentinel

Class Outer {
    public static volatile flag = true;

    Outer() {
        new Test().start();
    }
    class Test extends Thread {

        public void run() {
            while (Outer.flag) {
                //do stuff here
            }
        }
    }

}

ตั้งค่าตัวแปรคลาสภายนอกเช่น flag = true ในตัวอย่างด้านบน ตั้งค่าเป็นเท็จเพื่อ 'ฆ่า' เธรด


2
เช่นเดียวกับคำใบ้ข้าง: ตัวแปรที่มีการตั้งค่าสถานะใช้งานได้เฉพาะเมื่อเธรดทำงานและไม่ติดขัด Thread.interrupt () ควรปล่อยเธรดให้อยู่ในสภาพรอคอยส่วนใหญ่ (รอ, พักการอ่าน, เครือข่ายและอื่น ๆ ) ดังนั้นคุณไม่ควรไม่เคยใช้ InterruptedException เพื่อทำงานนี้
ReneS

12
สิ่งนี้ไม่น่าเชื่อถือ ทำ "ตั้งค่าสถานะ" volatileเพื่อให้แน่ใจว่าทำงานได้อย่างถูกต้องทุกที่ คลาสภายในไม่คงที่ดังนั้นแฟล็กควรเป็นตัวแปรอินสแตนซ์ ควรล้างค่าสถานะในวิธีการเข้าถึงเพื่อให้การดำเนินการอื่น ๆ (เช่นการขัดจังหวะ) สามารถทำได้ ชื่อ "flag" ไม่ใช่คำอธิบาย
erickson

2
ฉันไม่ได้รับสิ่ง "ในขณะที่" ในวิธีการเรียกใช้ นี่ไม่ได้หมายความว่าสิ่งใดก็ตามที่เขียนในวิธีการเรียกใช้จะถูกทำซ้ำ? นี่ไม่ใช่สิ่งที่เราต้องการให้เธรดทำตั้งแต่แรก :(

2
+1 กำลังทำในขณะที่ (! Thread.currentThread (). isInteruppted ()) เป็นที่ต้องการ
Toby

2
ทั้งสองกรณีล้มเหลวเมื่อเช่นคุณเปิดกระบวนการภายนอกในขณะที่ {// open ext process} และกระบวนการนั้นถูกแขวนไว้ตอนนี้เธรดทั้งสองจะไม่ถูกขัดจังหวะและจะถึงจุดสิ้นสุดเพื่อตรวจสอบเงื่อนไขบูลีนของคุณและคุณ ค้างไว้ ... ลองเล่นด้วยเช่นเปิดคอนโซล python โดยใช้ java.exec และลองรับการควบคุมกลับโดยไม่ต้องเขียน exit และดูว่ามีวิธีฆ่ากระบวนการนั้นและออกไป .... ไม่มีทางที่จะ ออกไปจากสถานการณ์เช่นนี้ ...
Space Rocker

11

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

Thread f = <A thread to be stopped>
Method m = Thread.class.getDeclaredMethod( "stop0" , new Class[]{Object.class} );
m.setAccessible( true );
m.invoke( f , new ThreadDeath() );

2
ไม่มีเหตุผลที่จะทำเช่นนี้เพราะมันยังคงเป็นไปได้ที่จะเรียกประชาชนThread.stopแม้ว่ามันจะเลิก
Lii

1
@Lii Thread.stopทำสิ่งเดียวกัน แต่ตรวจสอบการเข้าถึงและการอนุญาต การใช้Thread.stopค่อนข้างชัดเจนและฉันจำไม่ได้ว่าทำไมฉันถึงใช้Thread.stop0แทนสิ่งนั้น อาจจะThread.stopไม่ได้ผลกับกรณีพิเศษของฉัน (Weblogic บน Java 6) หรืออาจThread.stopเป็นเพราะเลิกใช้แล้วทำให้เกิดการเตือน
VadimPlatonov

1
ในสถานการณ์ของฉันนี่เป็นวิธีเดียวที่จะหยุดการทำงานเธรดที่ไม่มีที่สิ้นสุด ด้วยเหตุผลบางอย่าง. stop () ไม่ได้หยุดเธรด แต่ stop0 () ได้
fiffy

10

ฉันต้องการเพิ่มข้อสังเกตหลายประการโดยอิงจากความคิดเห็นที่สะสมไว้

  1. Thread.stop() จะหยุดเธรดหากตัวจัดการความปลอดภัยอนุญาต
  2. Thread.stop()อันตราย. ต้องบอกว่าถ้าคุณกำลังทำงานในสภาพแวดล้อม JEE และคุณไม่สามารถควบคุมรหัสที่ถูกเรียกได้อาจจำเป็น เห็นทำไม Thread.stop เลิกใช้?
  3. คุณไม่ควรหยุดหยุดด้ายผู้ปฏิบัติงานตู้คอนเทนเนอร์ หากคุณต้องการเรียกใช้รหัสที่มีแนวโน้มที่จะวาง (อย่างระมัดระวัง) เริ่มเธรดภูตใหม่และตรวจสอบมันฆ่าถ้าจำเป็น
  4. stop()สร้างThreadDeathErrorข้อผิดพลาดใหม่ในหัวข้อการโทรแล้วโยนข้อผิดพลาดนั้นบนเธรดเป้าหมาย ดังนั้นการติดตามสแต็กจึงไม่มีค่า
  5. ใน JRE 6 stop()ตรวจสอบกับผู้จัดการการรักษาความปลอดภัยและเรียกสายที่stop1() เป็นรหัสเนทีฟstop0()stop0()
  6. ในฐานะของ Java 13 Thread.stop()ยังไม่ถูกลบ (แต่) แต่Thread.stop(Throwable)ถูกลบใน Java 11 ( รายชื่อผู้รับจดหมาย , JDK-8204243 )

8

Thread.stop()ฉันจะลงคะแนนเสียงให้

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

ทั้งหมดนี้และเขาสามารถทำการประมวลผลการตอบสนองที่อาจรุนแรงของ CPU และคุณในฐานะนักพัฒนาไม่สามารถหยุดมันได้เพราะคุณไม่สามารถโยนif (Thread.currentThread().isInterrupted())บรรทัดในรหัสทั้งหมดได้

ดังนั้นการไร้ความสามารถในการหยุดเธรดอย่างแรงมันก็แปลก


หากการดำเนินการเครือข่ายถูกยกเลิกอย่างปลอดภัยอยู่แล้วเพียงขัดจังหวะเธรด หากการดำเนินการเครือข่ายไม่สามารถยกเลิกได้อย่างปลอดภัยคุณจะไม่สามารถโทรThread.stop()ได้อย่างปลอดภัย คุณยังไม่ได้ลงคะแนนThread.stop()คุณจะขอให้ทุกคนที่ดำเนินการทุกอย่างที่อาจใช้เวลานานในการยกเลิกอย่างปลอดภัย และนั่นอาจเป็นความคิดที่ดี แต่ก็ไม่มีอะไรเกี่ยวข้องกับการนำไปใช้Thread.stop()เป็นวิธีการทำแท้งที่ปลอดภัย เรามีอยู่แล้วinterruptสำหรับสิ่งนั้น
David Schwartz

"ดังนั้นการไร้ความสามารถในการหยุดเธรดมันอย่างประหลาด" - ... จนกว่าคุณจะมองลึก (ขณะที่นักออกแบบ Java ได้ทำ) stopและสรุปว่ามีการแก้ปัญหาไม่มีที่ทำงานได้ในทางเทคนิคที่ไม่ได้เลวร้ายยิ่งกว่าหึ
สตีเฟ่นซี

5

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

เพื่อจุดประสงค์นี้ฉันสร้างjkillthread ดูคำแนะนำสำหรับการใช้งาน


ขอบคุณ! สิ่งที่ฉันกำลังมองหา!
เดนิสโคโคริน

4

มีกรณีที่คุณกำลังเรียกใช้รหัสที่ไม่น่าเชื่อถือบางประเภท (ฉันมีสิ่งนี้เป็นการส่วนตัวโดยการอนุญาตให้สคริปต์ที่อัปโหลดสามารถทำงานในสภาพแวดล้อม Java ของฉันใช่มีสัญญาณเตือนความปลอดภัยดังขึ้นทุกที่ แต่เป็นส่วนหนึ่งของแอปพลิเคชัน) ในกรณีที่โชคร้ายนี้คุณเป็นคนแรก เพื่อเคารพสัญญาณบูลีนที่ทำงาน / ไม่ทำงานบางประเภท ความปลอดภัยที่ล้มเหลวเพียงอย่างเดียวของคุณคือการเรียกใช้เมธอด stop บนเธรดหากพูดว่ามันทำงานได้นานกว่าการหมดเวลาบางส่วน

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


บริการ AFAIK ที่เพิ่มมากขึ้นกำลังกลายเป็นระบบไฮบริดและใช้สภาพแวดล้อมที่มีการจัดการเพื่อรันโค้ดของบุคคลที่สาม (ปลั๊กอิน, สคริปต์, ฯลฯ ) ซึ่งพวกเขาไม่สามารถควบคุมรหัสได้อย่างเต็มที่ดูเหมือนว่าไม่มีเหตุผลที่จะถอดเธรดออกจากตาราง ตั้งแต่สำหรับวิศวกรบริการรัฐมีชีวิตอยู่และการให้บริการสามารถดีกว่ารัฐที่ไม่ได้ให้บริการอย่างใดอย่างหนึ่ง (เนื่องจากการแขวน (ซึ่งจะใช้เธรด) หรือยุ่งวนไม่สิ้นสุดไม่ว่าง (ซึ่งใช้แกนออกไป))
Weipeng L

3

ไม่มีทางที่จะฆ่าเธรดอย่างงดงามได้

คุณสามารถลองขัดจังหวะเธรดหนึ่งในกลยุทธ์ทั่วไปคือการใช้ยาพิษเพื่อส่งข้อความถึงเธรดเพื่อหยุดตัวเอง

public class CancelSupport {
    public static class CommandExecutor implements Runnable {
            private BlockingQueue<String> queue;
            public static final String POISON_PILL  = stopnow”;
            public CommandExecutor(BlockingQueue<String> queue) {
                    this.queue=queue;
            }
            @Override
            public void run() {
                    boolean stop=false;
                    while(!stop) {
                            try {
                                    String command=queue.take();
                                    if(POISON_PILL.equals(command)) {
                                            stop=true;
                                    } else {
                                            // do command
                                            System.out.println(command);
                                    }
                            } catch (InterruptedException e) {
                                    stop=true;
                            }
                    }
                    System.out.println(“Stopping execution”);
            }

    }

}

BlockingQueue<String> queue=new LinkedBlockingQueue<String>();
Thread t=new Thread(new CommandExecutor(queue));
queue.put(“hello”);
queue.put(“world”);
t.start();
Thread.sleep(1000);
queue.put(“stopnow”);

http://anandsekar.github.io/cancel-support-for-threads/


2

โดยทั่วไปคุณจะไม่ฆ่าหยุดหรือขัดจังหวะเธรด (หรือตรวจสอบว่ามันถูกขัดจังหวะ ()) แต่ปล่อยให้มันยุติโดยธรรมชาติ

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

วิธีนี้คุณฆ่าเธรดอย่างงดงาม :)


1

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

มีวิธีแก้ปัญหาหลักสองประการสำหรับการยุติการควบคุมเธรด:

  • การใช้แฟล็กการระเหยแบบแบ่งใช้
  • ใช้เมธอด Thread.interrupt () และ Thread.interrupted () คู่

คำอธิบายที่ดีและมีรายละเอียดของปัญหาที่เกี่ยวข้องกับการยกเลิกเธรดในทันทีรวมถึงตัวอย่างของการแก้ปัญหาที่ไม่ถูกต้องและเหมาะสมสำหรับการยกเลิกเธรดที่ควบคุมสามารถดูได้ที่นี่:

https://www.securecoding.cert.org/confluence/display/java/THI05-J.+Do+not+use+Thread.stop%28%29+to+terminate+threads


เนื่องจากโปรแกรมไม่ได้ถูกเขียนขึ้นโดยผู้พัฒนาเดี่ยวอีกต่อไปการฆ่าเธรดจึงเป็นสิ่งจำเป็น ดังนั้นจึงไม่สามารถพิจารณาการเขียนโปรแกรมที่ไม่ดี ฉันนึกภาพไม่ออกถ้าไม่ฆ่า Linux การไม่สามารถฆ่าเธรดเป็นข้อบกพร่องของ Java
Pavel Niedoba

1
เยี่ยมเลยนายถูกต้อง ... จะเป็นอย่างไรถ้าคุณต้องโทรหาห้องสมุดบุคคลที่สามซึ่งคุณไม่สามารถควบคุมได้และมีช่วงเวลาที่บั๊กกี้และอาจหยุดทุก 1,000-2,000 ครั้งเมื่อถูกประหารชีวิต? การเขียนโปรแกรมไม่ดีใช่มั้ย คุณไม่สามารถเข้าถึงรหัสที่คุณใช้อยู่เสมอ อย่างไรก็ตามผู้ปฏิบัติการขอให้ฆ่าเธรดไม่ใช่วิธีควบคุมการไหลของมันเมื่อออกแบบโค้ดของเขาเอง ...
Arturas M

คำถามคือจะเกิดอะไรขึ้นเมื่อคุณฆ่าเธรดที่มี mutex เป็นเจ้าของหรือมีการจัดสรรบล็อกหน่วยความจำบางส่วนหรือซึ่งควรสร้างเหตุการณ์หรือข้อมูลที่เธรดอื่นกำลังรออยู่ จะเกิดอะไรขึ้นกับตรรกะส่วนที่เหลือของแอปพลิเคชันของคุณ? คุณจะตกอยู่ในความเสี่ยงเสมอว่าปัญหาเล็กและชัดเจนจะถูกแปลงเป็นปัญหาที่ซับซ้อนซึ่งยากที่จะทำซ้ำและตรวจสอบ การฆ่าเธรดไม่ปลอดภัยเนื่องจากอาจทำให้แอปพลิเคชันของคุณอยู่ในสถานะที่ไม่สอดคล้องกันหลายประการ ดูข้อมูลจากลิงค์ใน cert.org
ZarathustrA

เรามีเธรดควบคุมที่ในเงื่อนไขบางอย่างอาจตัดสินใจว่าการคำนวณทั้งหมดกลายเป็นสิ่งที่ไม่มีประโยชน์ runnables ที่แตกต่างกันจำนวนมากในการทำงานจริงจะต้องสาดกับตัวแปรของ isInterrupted () ในสถานที่ที่สะดวกใด ๆ - วิธีที่น่ากลัว! มันเป็นเรื่องที่ดีกว่านี้ถ้าตัวควบคุมทำให้ ThreadDeath ดูเหมือนจะลอยขึ้นมาจากไหนไม่รู้คลี่คลายการซิงโครไนซ์ & บล็อกทั้งหมดในที่สุด ทุกคนบอกว่านี่เป็นข้อผิดพลาดได้ง่าย แต่สำหรับเธรดที่ไม่เกี่ยวข้องอย่างเป็นธรรมฉันไม่เห็นสาเหตุ
แดเนียล


1

ฉันไม่ได้ขัดจังหวะการทำงานใน Android ดังนั้นฉันจึงใช้วิธีนี้ทำงานได้อย่างสมบูรณ์แบบ:

boolean shouldCheckUpdates = true;

private void startupCheckForUpdatesEveryFewSeconds() {
    Thread t = new Thread(new CheckUpdates());
    t.start();
}

private class CheckUpdates implements Runnable{
    public void run() {
        while (shouldCheckUpdates){
            //Thread sleep 3 seconds
            System.out.println("Do your thing here");
        }
    }
}

 public void stop(){
        shouldCheckUpdates = false;
 }

2
ควรเพิ่มคีย์เวิร์ดที่ลบเลือนไปใน
clinux

1

'การฆ่าเธรด' ไม่ใช่วลีที่ถูกต้องที่จะใช้ นี่คือวิธีหนึ่งที่เราสามารถใช้งานเสร็จสมบูรณ์ / ออกของด้ายบนจะ:

Runnable ที่ฉันใช้:

class TaskThread implements Runnable {

    boolean shouldStop;

    public TaskThread(boolean shouldStop) {
        this.shouldStop = shouldStop;
    }

    @Override
    public void run() {

        System.out.println("Thread has started");

        while (!shouldStop) {
            // do something
        }

        System.out.println("Thread has ended");

    }

    public void stop() {
        shouldStop = true;
    }

}

คลาสที่เรียกใช้:

public class ThreadStop {

    public static void main(String[] args) {

        System.out.println("Start");

        // Start the thread
        TaskThread task = new TaskThread(false);
        Thread t = new Thread(task);
        t.start();

        // Stop the thread
        task.stop();

        System.out.println("End");

    }

}

ควรเพิ่มคีย์เวิร์ดที่มีความผันผวนไปยังตัวแปร shouldStop ในกรณีที่คอมไพเลอร์ปรับให้เหมาะสมกับหน่วยเก็บข้อมูลโลคัลเธรด
Oleksii Kyslytsyn

0

Thread.stop เลิกใช้แล้วเราจะหยุดเธรดใน java อย่างไร?

ใช้วิธีการขัดจังหวะและในอนาคตเพื่อขอยกเลิกเสมอ

  1. เมื่องานตอบสนองต่อสัญญาณขัดจังหวะตัวอย่างเช่นการปิดกั้นคิวใช้วิธี
Callable < String > callable = new Callable < String > () {
    @Override
    public String call() throws Exception {
        String result = "";
        try {
            //assume below take method is blocked as no work is produced.
            result = queue.take();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return result;
    }
};
Future future = executor.submit(callable);
try {
    String result = future.get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
    logger.error("Thread timedout!");
    return "";
} finally {
    //this will call interrupt on queue which will abort the operation.
    //if it completes before time out, it has no side effects
    future.cancel(true);
}
  1. เมื่องานไม่ตอบสนองต่อสัญญาณขัดจังหวะจัดหางานที่ดำเนินการซ็อกเก็ต I / O ซึ่งไม่ตอบสนองต่อสัญญาณขัดจังหวะและใช้วิธีการดังกล่าวข้างต้นจะไม่ยกเลิกงานในอนาคตจะหมดเวลา แต่การยกเลิกในบล็อกในที่สุดจะไม่มีผล ด้ายจะยังคงฟังซ็อกเก็ต เราสามารถปิดซ็อกเก็ตหรือโทรวิธีการปิดการเชื่อมต่อหากดำเนินการโดยสระว่ายน้ำ
public interface CustomCallable < T > extends Callable < T > {
    void cancel();
    RunnableFuture < T > newTask();
}

public class CustomExecutorPool extends ThreadPoolExecutor {
    protected < T > RunnableFuture < T > newTaskFor(Callable < T > callable) {
        if (callable instanceof CancellableTask)
            return ((CancellableTask < T > ) callable).newTask();
        else
            return super.newTaskFor(callable);
    }
}

public abstract class UnblockingIOTask < T > implements CustomCallable < T > {
    public synchronized void cancel() {
        try {
            obj.close();
        } catch (IOException e) {
            logger.error("io exception", e);
        }
    }

    public RunnableFuture < T > newTask() {
        return new FutureTask < T > (this) {
            public boolean cancel(boolean mayInterruptIfRunning) {
                try {
                    this.cancel();
                } finally {
                    return super.cancel(mayInterruptIfRunning);
                }
            }

        };
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.