2010-04-28 4 views
26

जावा में कुछ निर्दिष्ट समय सीमा के बाद बच्चे धागे को मारने का कोई तरीका है? संपादित करें: यह भी विशेष धागा अपने सबसे खराब मामले में अवरुद्ध हो सकता है (थ्रेड का उपयोग फ़ाइल संशोधन और ब्लॉक के लिए प्रतीक्षा करने के लिए किया जाता है जब तक कि यह घटना न हो), तो मुझे यकीन नहीं है कि इंटरप्ट() सफल होगा?जावा में कुछ निर्दिष्ट समय सीमा के बाद थ्रेड को मारना

+0

आप के लिए प्रतीक्षा करने का उपयोग कर रहे हैं फ़ाइल संशोधन? ऑब्जेक्ट.वाइट() या कुछ और? – mdma

+0

दरअसल मैं फ़ाइल संशोधनों और विशेष रूप से 'watchService.take()' को देखने के लिए jpathwatch का उपयोग कर रहा हूं जो तब तक अवरुद्ध होगा जब तक कोई फ़ाइल बनाई/हटाई नहीं जाती है। – Traker

उत्तर

33

Runnable निष्पादित करने के लिए ExecutorService का उपयोग करें, उन विधियों को चेकआउट करें जिनमें आप टाइमआउट निर्दिष्ट कर सकते हैं। जैसे

ExecutorService executor = Executors.newSingleThreadExecutor(); 
executor.invokeAll(Arrays.asList(new Task()), 10, TimeUnit.MINUTES); // Timeout of 10 minutes. 
executor.shutdown(); 

यहाँ Task निश्चित रूप से Runnable लागू करता है।

+0

अच्छे सुझाव, लेकिन क्या निष्पादक सेवा अवरुद्ध होने पर भी थ्रेड को समाप्त करने में सक्षम होगी? – Traker

+1

यह थ्रेड को बाधित करेगा, हां। यदि आप इसे हुक करना चाहते हैं, तो 'निष्पादक सेवा # प्रतीक्षा करें) (') का उपयोग करें, जवाडोक के परिचय में भी उदाहरण देखें। – BalusC

+14

आईएमएचओ, 'invokeAll' ओवरकिल है। बस 'execor.submit (नया कार्य()) का उपयोग करें। (10, TimeUnit.MINUTES) प्राप्त करें; ' –

5

क्यों interrupt() किसी विशेष समय के बाद नहीं? आपके स्पॉन्टेड थ्रेड को InterruptedException को ठीक से संभालने में सक्षम होना होगा।

धागे को बंद करने के बारे में अधिक जानकारी के लिए इस आलेख को देखें (http://www.javaspecialists.eu/archive/Issue056.html)।

निष्पादक/भविष्य ढांचे को भी देखें, जो परिणाम एकत्र करने और/या विशेष समय सीमा के भीतर धागे को समाप्त करने के लिए उपयोगी विधियां प्रदान करता है।

+1

थ्रेड को केवल 'इंटरप्टेड एक्सेप्शन' का जवाब देना होगा यदि यह कॉल करता है जो इसे फेंक सकता है। यदि यह एक लूप में कताई कर रहा है, तो इसे 'थ्रेड.इस इंटरप्टेड() '(या केवल' थ्रेड। इंटरप्टेड() 'का उपयोग करके अपने स्वयं के बाधित झंडे की जांच करनी चाहिए, जो वर्तमान धागे को दर्शाती है)। –

0

धागे को मारना आम तौर पर Thread के लिए एपीआई दस्तावेज़ों से जुड़े कारणों के लिए एक बुरा विचार है।

यदि आप हत्या पर मृत सेट हैं, तो पूरी नई प्रक्रिया का उपयोग करें।

अन्यथा सामान्य बात यह है कि थ्रेड पोल System.nanoTime है, एक मतदान (संभव volatile) ध्वज, एक "जहर गोली" या उस प्रकृति के कुछ को कतार दें।

+0

धागे को मारना महत्वपूर्ण हो सकता है, अगर आपके पास यह धागा चलाने वाला कोड नहीं है, और आपको यह सुनिश्चित करना होगा कि वह मर चुका है। कभी-कभी आपके पास दोनों वर्चुअल एड्रेस में कोड चलाना चाहिए। –

+0

@ एलाजार यह लगभग निश्चित रूप से अधिक महत्वपूर्ण है कि प्रक्रिया स्थिर बनी हुई है। –

0

ब्रायन का अधिकार, इसे अवरुद्ध करना धागे को "रोकना" से सुरक्षित है।
क्या होगा यदि थ्रेड किसी ऑब्जेक्ट को मध्य-संशोधन पर लॉक कर रहा है, और अचानक बंद हो जाता है (जिससे लॉक जारी किया जा सकता है)? आपको अजीब परिणाम मिलते हैं।

4

सीधे नहीं; मुझे लगता है कि उस समय सीमा के साथ उस थ्रेड पर() को शामिल करने का सबसे आसान तरीका है, और थ्रेड को बाधित करें यदि यह समाप्ति के समय तक नहीं किया जाता है।

तो,

Thread t = ... 
t.join(timelimit); 
if (t.isAlive) t.interrupt(); 

सूचना मैं बजाय वास्तव में यह हत्या की बाधा का इस्तेमाल किया है, यह ज्यादा सुरक्षित है। मैं सीधे धागे में हेरफेर करने के बजाय निष्पादकों का उपयोग करने की भी सिफारिश करता हूं।

+0

यदि अन्य थ्रेड सभी CPU को पकड़ लेता है तो यह ठीक से काम नहीं करेगा, इस प्रकार जुड़ने में बहुत बड़ी देरी के बाद केवल _started_ है। – mafu

+0

मुझे लगता है कि 'अगर (t.isAlive()) ' – PHPirate

0

destroy() का उपयोग न करें क्योंकि यह कोई सफाई नहीं करता है।

सबसे सीधा रास्ता तरह

try { 
    thread.join(); 
} catch (InterruptedException e) {//log exception...} 

join() उपयोग करने के लिए, आप एक ExecutorService इस्तेमाल कर सकते हैं है। अगर आपके पास कई धागे एक साथ चल रहे हैं तो इससे बहुत समझदारी होगी। यदि आपको अन्य धागे चलने के दौरान नए धागे को बढ़ाने की आवश्यकता है, तो आप इसे BlockingQueue के साथ जोड़ सकते हैं।

ThreadPoolExecutor (एक ExecutorService-कार्यान्वयन) BlockingQueue तर्क के रूप में ले सकता है, और आप बस कतार में नए धागे जोड़ सकते हैं। जब आप पूरा कर लेंगे तो आप ThreadPoolExecutor को समाप्त कर दें।

private BlockingQueue<Runnable> queue; 
... 
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, new Long(1000), 
       TimeUnit.MILLISECONDS, this.queue); 

आप कतार में जोड़े गए सभी थ्रेडों की गिनती रख सकते हैं। जब आपको लगता है आप कर चुके हैं (कतार खाली है, शायद?) बस

if (issuedThreads == pool.getCompletedTaskCount()) { 
     pool.shutdown(); 
    } 

को यह तुलना दो मैच, आप कर रहे हैं, तो। (मैं एक डेवलपर हूँ) jcabi-aspects से अपने विधि के लिए

try { 
     while (!this.pool.awaitTermination(1000, TimeUnit.MILLISECONDS)); 
} catch (InterruptedException e) {//log exception...} 
1

आप AOP उपयोग कर सकते हैं और एक @Timeable एनोटेशन: एक और तरीका है पूल समाप्त करने के लिए एक पाश में एक दूसरे इंतज़ार करना है

@Timeable(limit = 1, unit = TimeUnit.SECONDS) 
String load(String resource) { 
    // do something time consuming 
} 

जब समय सीमा तक पहुंच जाती है तो आपके धागे को interrupted() ध्वज true पर सेट किया जाएगा और यह स्थिति सही ढंग से संभालने और निष्पादन को रोकने के लिए आपका काम है। आम तौर पर यह Thread.sleep(..) द्वारा किया जाता है।

0

कुछ उपयोगी परिवर्तन, जावा 9. के बाद से CompletableFuture में JEP 266 के हिस्से के रूप पेश किए गए अब के लिए orTimeout पद्धति का उपयोग करना, यह संभव है यह पसंद लिखने के लिए:

CompletableFuture.runAsync(thread::run) 
    .orTimeout(30, TimeUnit.SECONDS) 
    .exceptionally(throwable -> { 
     log.error("An error occurred", throwable); 
     return null; 
    }); 

जावा 8 में, दुर्भाग्य से, आप का उपयोग करना चाहिए कुछ अतिरिक्त कोड। यहाँ Lombok की मदद से प्रतिनिधिमंडल पैटर्न उपयोग के एक उदाहरण है:

import com.google.common.util.concurrent.ThreadFactoryBuilder; 
import java.time.Duration; 
import java.util.concurrent.CompletableFuture; 
import java.util.concurrent.Executors; 
import static java.util.concurrent.TimeUnit.MILLISECONDS; 
import java.util.concurrent.TimeoutException; 
import static lombok.AccessLevel.PRIVATE; 
import lombok.AllArgsConstructor; 
import lombok.experimental.Delegate; 

@AllArgsConstructor(access = PRIVATE) 
public class TimeoutableCompletableFuture<T> extends CompletableFuture<T> { 

    public static TimeoutableCompletableFuture<Void> runAsync(
      Runnable runnable) { 
     return new TimeoutableCompletableFuture<>(
       CompletableFuture.runAsync(runnable)); 
    } 

    @Delegate 
    private final CompletableFuture<T> baseFuture; 

    public TimeoutableCompletableFuture<T> orTimeout(Duration duration) { 
     final CompletableFuture<T> otherFuture = new CompletableFuture<>(); 
     Executors.newScheduledThreadPool(
       1, 
       new ThreadFactoryBuilder() 
       .setDaemon(true) 
       .setNameFormat("timeoutable-%d") 
       .build()) 
       .schedule(() -> { 
        TimeoutException ex = new TimeoutException(
          "Timeout after " + duration); 
        return otherFuture.completeExceptionally(ex); 
       }, duration.toMillis(), MILLISECONDS); 

     return new TimeoutableCompletableFuture<>(
       baseFuture.applyToEither(otherFuture, a -> a)); 
    } 
} 

बेशक, कोड आसानी से ऊपर सिर्फ एक स्थिर कारखाने पद्धति के रूप में फिर से लिखा जा सकता है:

public static CompletableFuture<Void> runAsyncOrTimeout(
     Runnable runnable, long timeout, TimeUnit unit) { 

    CompletableFuture<Void> other = new CompletableFuture<>(); 
    Executors.newScheduledThreadPool(
      1, 
      new ThreadFactoryBuilder() 
      .setDaemon(true) 
      .setNameFormat("timeoutafter-%d") 
      .build()) 
      .schedule(() -> { 
       TimeoutException ex = new TimeoutException(
         "Timeout after " + timeout); 
       return other.completeExceptionally(ex); 
      }, timeout, unit); 
    return CompletableFuture.runAsync(runnable).applyToEither(other, a -> a); 
} 
संबंधित मुद्दे