จะเรียกเมธอดด้วยเธรดแยกต่างหากใน Java ได้อย่างไร?


126

doWork()สมมติว่าผมมีวิธีการ ฉันจะเรียกมันจากเธรดแยกต่างหากได้อย่างไร (ไม่ใช่เธรดหลัก)


มีตัวอย่างบางส่วนเกี่ยวกับคำถามที่เกี่ยวข้องล่าสุดนี้: การฆ่าวนรอบที่ไม่มีที่สิ้นสุดใน java
Greg Hewgill

stackoverflow.com/questions/36832094/…ฉันมีปัญหาที่คล้ายกันโปรดช่วยฉันแก้ปัญหานี้
Sruthi Acg

คุณอาจต้องการดู Reactive Java blog.danlew.net/2014/09/15/grokking-rxjava-part-1สำหรับงานแบบอะซิงโครนัส
Nathan Dunn

คำตอบ:


138

สร้างคลาสที่ใช้Runnableอินเทอร์เฟซ ใส่รหัสที่คุณต้องการเรียกใช้ในrun()วิธีการซึ่งเป็นวิธีการที่คุณต้องเขียนเพื่อให้สอดคล้องกับRunnableอินเทอร์เฟซ ในเธรด "หลัก" ของคุณสร้างThreadคลาสใหม่ส่งตัวสร้างอินสแตนซ์ของคุณRunnableจากนั้นเรียกstart()ใช้ startบอกให้ JVM ใช้เวทมนตร์เพื่อสร้างเธรดใหม่จากนั้นเรียกrunใช้เมธอดของคุณในเธรดใหม่นั้น

public class MyRunnable implements Runnable {

    private int var;

    public MyRunnable(int var) {
        this.var = var;
    }

    public void run() {
        // code in the other thread, can reference "var" variable
    }
}

public class MainThreadClass {
    public static void main(String args[]) {
        MyRunnable myRunnable = new MyRunnable(10);
        Thread t = new Thread(myRunnable)
        t.start();
    }    
}

ดูบทแนะนำการทำงานพร้อมกันของ Javaเพื่อเริ่มต้น

หากมีการเรียกวิธีการของคุณบ่อยๆการสร้างเธรดใหม่ในแต่ละครั้งอาจไม่คุ้มค่าเนื่องจากเป็นการดำเนินการที่มีราคาแพง อาจเป็นการดีที่สุดที่จะใช้กลุ่มเธรดบางประเภท มีลักษณะที่Future, Callable, Executorเรียนในjava.util.concurrentแพคเกจ


1
จะเป็นอย่างไรหากมีตัวแปรที่คุณต้องการส่งผ่าน
Louis Rhys

8
run()วิธีจะไม่มีพารามิเตอร์ดังนั้นคุณจึงไม่สามารถส่งผ่านตัวแปรมี ฉันขอแนะนำให้คุณส่งผ่านในตัวสร้าง - ฉันจะแก้ไขคำตอบเพื่อแสดงให้เห็นว่า
Noel M

1
มีวิธีสั้น ๆ สำหรับการเรียก 1 วิธีในชุดข้อความอื่นหรือไม่? ฉันรู้new Thread() { public void run() {myMethod();}}.start();วิธีนั้นสั้นที่สุด?
Steven Roose

@NoelM คุณสามารถอธิบายความแตกต่างระหว่างคำตอบของคุณกับ MANN ได้หรือไม่?
Asif Mushtaq

2
คำตอบของ MANN ใช้การดำเนินการที่ไม่ระบุชื่อของRunnable- Runnableฉันเป็นคลาสที่ขยาย และเนื่องจากฉันได้ทำไปแล้วว่าฉันมีตัวสร้างของตัวเองซึ่งส่งผ่านสถานะไปยังวัตถุที่สร้างอินสแตนซ์
Noel M

183
Thread t1 = new Thread(new Runnable() {
    @Override
    public void run() {
        // code goes here.
    }
});  
t1.start();

หรือ

new Thread(new Runnable() {
     @Override
     public void run() {
          // code goes here.
     }
}).start();

หรือ

new Thread(() -> {
    // code goes here.
}).start();

หรือ

Executors.newSingleThreadExecutor().execute(new Runnable() {
    @Override
    public void run() {
        myCustomMethod();
    }
});

หรือ

Executors.newCachedThreadPool().execute(new Runnable() {
    @Override
    public void run() {
        myCustomMethod();
    }
});

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

@ Ashish: โปรดอธิบายว่ามีการแก้ไขอะไรและทำไม?
MANN

1
@AshishAggarwal: ดูแปลกสำหรับฉันเมื่อมีคนทำโดยไม่ได้รับอนุญาตจากผู้เขียน!
MANN

@MANN คุณสามารถอธิบายได้ว่าทำไมคุณถึงใช้วิธีการรันในพารามิเตอร์เธรด ประสิทธิภาพที่ดีขึ้น?
Asif Mushtaq

1
เราจำเป็นต้องยุติเธรดอย่างชัดเจนหรือไม่? ไม่มีความเสี่ยงในการสร้างหน่วยความจำรั่วโดยไม่ยุติเธรดอย่างชัดเจนหรือไม่? หรือเธรดจะสิ้นสุดเมื่อเสร็จสิ้นด้วยrun()?
theyuv

59

ใน Java 8 คุณสามารถทำได้ด้วยโค้ดหนึ่งบรรทัด

หากวิธีการของคุณไม่ใช้พารามิเตอร์ใด ๆ คุณสามารถใช้การอ้างอิงวิธีการ:

new Thread(MyClass::doWork).start();

มิฉะนั้นคุณสามารถเรียกใช้เมธอดในนิพจน์แลมบ์ดา:

new Thread(() -> doWork(someParam)).start();

ขออภัยที่นำสิ่งนี้กลับมา แต่->หมายความว่าอย่างไร
Kyle

1
นั่นคือไวยากรณ์ที่ใช้สร้างนิพจน์แลมบ์ดา ดูลิงค์เหล่านี้สำหรับข้อมูลเพิ่มเติม: '->' ทำอะไรใน Java , และ บทช่วยสอน Java ™ - Lambda Expressions
Aaron Cohn

@AaronCohn คนที่ยอดเยี่ยม! คุณรู้จักทางเลือกอื่นสำหรับเธรดใน Java หรือไม่? ฉันมาจากโลก Python โดยที่เราจะใช้Celery task queueสำหรับสิ่งที่ไม่ตรงกัน
CESCO

Java มีabstractions ระดับสูงกว่าสำหรับจัดการกับ Threadsแต่คุณอาจกำลังมองหาสิ่งที่คล้ายกับAkka ?
Aaron Cohn

7

อีกตัวเลือกหนึ่งที่เร็วกว่าในการเรียกสิ่งต่างๆ (เช่น DialogBoxes และ MessageBoxes และการสร้างเธรดแยกต่างหากสำหรับวิธีการที่ไม่ปลอดภัยของเธรด) คือการใช้ Lamba Expression

  new Thread(() -> {
                      "code here"
            }).start();

3

เมื่อไม่นานมานี้ฉันได้เขียนคลาสยูทิลิตี้ง่ายๆที่ใช้บริการตัวดำเนินการ JDK5 และดำเนินการกระบวนการเฉพาะในพื้นหลัง เนื่องจากโดยทั่วไปแล้ว doWork () จะมีค่าส่งคืนเป็นโมฆะคุณอาจต้องการใช้คลาสยูทิลิตี้นี้เพื่อดำเนินการในพื้นหลัง

ดูบทความนี้ที่ฉันได้บันทึกยูทิลิตี้นี้


6
อนาคตและโทรได้ทำสิ่งนี้ให้คุณ
Amir Afghani

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

ลิงก์เสีย (404)
palacsint

3

เพื่อให้บรรลุสิ่งนี้ด้วย RxJava 2.x คุณสามารถใช้:

Completable.fromAction(this::dowork).subscribeOn(Schedulers.io().subscribe();

subscribeOn()วิธีการระบุที่ตารางเวลาที่จะเรียกการกระทำบน - RxJava มีกำหนดการที่กำหนดไว้ล่วงหน้าหลายแห่งรวมถึงSchedulers.io()ที่มีสระว่ายน้ำด้ายไว้สำหรับการดำเนินการ I / O และSchedulers.computation()ซึ่งมีวัตถุประสงค์สำหรับการดำเนินการอย่างเข้มข้น CPU


3

หากคุณใช้ Java 8 เป็นอย่างน้อยคุณสามารถใช้เมธอดrunAsyncจากคลาสCompletableFuture

CompletableFuture.runAsync(() -> {...});

หากคุณต้องการส่งคืนผลลัพธ์ให้ใช้supplyAsyncแทน

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