ทุกคนสามารถแนะนำให้ฉันรู้ว่าฉันจะส่งพารามิเตอร์ให้เธรดได้อย่างไร?
นอกจากนี้มันทำงานอย่างไรกับคลาสที่ไม่ระบุชื่อ
Consumer<T>
ตอนนี้คุณสามารถใช้
ทุกคนสามารถแนะนำให้ฉันรู้ว่าฉันจะส่งพารามิเตอร์ให้เธรดได้อย่างไร?
นอกจากนี้มันทำงานอย่างไรกับคลาสที่ไม่ระบุชื่อ
Consumer<T>
ตอนนี้คุณสามารถใช้
คำตอบ:
คุณต้องผ่านพารามิเตอร์ในตัวสร้างไปยังวัตถุ Runnable:
public class MyRunnable implements Runnable {
public MyRunnable(Object parameter) {
// store parameter for later user
}
public void run() {
}
}
และก่อให้เกิดมัน:
Runnable r = new MyRunnable(param_value);
new Thread(r).start();
r
จะมีอาร์กิวเมนต์เดียวกันดังนั้นหากเราต้องการส่งอาร์กิวเมนต์ที่แตกต่างกันไปยังเธรดที่กำลังรันหลายเธรดMyThread
เราจำเป็นต้องสร้างMyThread
อินสแตนซ์ใหม่โดยใช้อาร์กิวเมนต์ที่ต้องการสำหรับแต่ละเธรด กล่าวอีกนัยหนึ่งเพื่อสร้างเธรดและทำงานเราจำเป็นต้องสร้างวัตถุสองอัน ได้แก่ Thread และ MyThread สิ่งนี้ถือว่าแย่ประสิทธิภาพฉลาดหรือไม่?
ในการตอบคำถามการแก้ไขที่นี่เป็นวิธีการทำงานสำหรับคลาสที่ไม่เปิดเผยตัวตน
final X parameter = ...; // the final is important
Thread t = new Thread(new Runnable() {
p = parameter;
public void run() {
...
};
t.start();
คุณมีคลาสที่ขยายเธรด (หรือเรียกใช้เรียกใช้) และตัวสร้างพร้อมพารามิเตอร์ที่คุณต้องการส่ง จากนั้นเมื่อคุณสร้างเธรดใหม่คุณต้องผ่านอาร์กิวเมนต์และเริ่มเธรดดังนี้:
Thread t = new MyThread(args...);
t.start();
Runnable เป็นทางออกที่ดีกว่า Thread BTW ดังนั้นฉันต้องการ:
public class MyRunnable implements Runnable {
private X parameter;
public MyRunnable(X parameter) {
this.parameter = parameter;
}
public void run() {
}
}
Thread t = new Thread(new MyRunnable(parameter));
t.start();
คำตอบนี้โดยทั่วไปเหมือนกับคำถามที่คล้ายกันนี้: วิธีส่งพารามิเตอร์ไปยังวัตถุ Thread
parameter
ได้โดยตรงจากrun()
วิธีการโดยไม่ต้องใช้ฟิลด์อย่างp
ที่ทุกคน ดูเหมือนว่าจะทำงาน มีบางสิ่งบางอย่าง multithreading ที่ละเอียดอ่อนที่ฉันหายไปโดยไม่คัดลอกparameter
ไปp
ไว้ล่วงหน้าหรือไม่?
)
ตัวอย่างแรกไปแล้ว
final X parameter
ก่อนหน้าnew Runnable()
จากนั้นฉันก็สามารถparameter
เข้าไปข้างในrun()
ได้ p = parameter
ฉันไม่จำเป็นต้องทำพิเศษ
final
ไม่สำคัญอีกต่อไป; ก็พอถ้าตัวแปรสุดท้ายได้อย่างมีประสิทธิภาพ (แม้จะไม่เป็นอันตรายต่อมัน)
ผ่าน Constructor ของ Runnable หรือ Thread class
class MyThread extends Thread {
private String to;
public MyThread(String to) {
this.to = to;
}
@Override
public void run() {
System.out.println("hello " + to);
}
}
public static void main(String[] args) {
new MyThread("world!").start();
}
@Override
เพื่อ?
@Override
ระบุอย่างชัดเจนว่ามีการแทนที่เมธอด abstract ในคลาส Thread
คำตอบนี้มาช้ามาก แต่อาจมีบางคนคิดว่ามันมีประโยชน์ มันเกี่ยวกับวิธีการส่งพารามิเตอร์ไปยัง a Runnable
โดยไม่ต้องประกาศ class ที่มีชื่อ
String someValue = "Just a demo, really...";
new Thread(new Runnable() {
private String myParam;
public Runnable init(String myParam) {
this.myParam = myParam;
return this;
}
@Override
public void run() {
System.out.println("This is called from another thread.");
System.out.println(this.myParam);
}
}.init(someValue)).start();
แน่นอนว่าคุณสามารถเลื่อนการดำเนินการstart
ไปเป็นช่วงเวลาที่สะดวกกว่าหรือเหมาะสมกว่าได้ และมันก็ขึ้นอยู่กับคุณว่าอะไรจะเป็นลายเซ็นของinit
วิธีการ (ดังนั้นจึงอาจใช้เวลามากขึ้นและ / หรือข้อโต้แย้งที่แตกต่างกัน) และแน่นอนแม้กระทั่งชื่อของมัน แต่โดยทั่วไปคุณจะได้รับความคิด
ในความเป็นจริงยังมีอีกวิธีหนึ่งในการส่งพารามิเตอร์ไปยังคลาสที่ไม่ระบุชื่อด้วยการใช้บล็อก initializer พิจารณาสิ่งนี้:
String someValue = "Another demo, no serious thing...";
int anotherValue = 42;
new Thread(new Runnable() {
private String myParam;
private int myOtherParam;
{
this.myParam = someValue;
this.myOtherParam = anotherValue;
}
@Override
public void run() {
System.out.println("This comes from another thread.");
System.out.println(this.myParam + ", " + this.myOtherParam);
}
}).start();
ดังนั้นทั้งหมดเกิดขึ้นภายในบล็อก initializer
this.myParam
จำเป็นจริงๆหรือ? คุณไม่สามารถวางตัวแปรส่วนตัวและอ้างอิงตัวแปรจากขอบเขตด้านนอกได้หรือไม่ ฉันเข้าใจ (แน่นอน) ว่าสิ่งนี้มีความหมายบางอย่างเช่นตัวแปรที่เปิดให้เปลี่ยนหลังจากเริ่มเธรด
Runnable
เมื่อคุณสร้างหัวข้อที่คุณจะต้องตัวอย่างของ วิธีที่ง่ายที่สุดในการส่งผ่านพารามิเตอร์จะเป็นการส่งผ่านเป็นอาร์กิวเมนต์ให้กับตัวสร้าง:
public class MyRunnable implements Runnable {
private volatile String myParam;
public MyRunnable(String myParam){
this.myParam = myParam;
...
}
public void run(){
// do something with myParam here
...
}
}
MyRunnable myRunnable = new myRunnable("Hello World");
new Thread(myRunnable).start();
หากคุณต้องการเปลี่ยนพารามิเตอร์ในขณะที่เธรดกำลังทำงานอยู่คุณสามารถเพิ่มเมธอด setter ให้กับคลาสที่รันได้ของคุณ:
public void setMyParam(String value){
this.myParam = value;
}
เมื่อคุณมีสิ่งนี้คุณสามารถเปลี่ยนค่าของพารามิเตอร์ได้โดยการเรียกสิ่งนี้:
myRunnable.setMyParam("Goodbye World");
แน่นอนถ้าคุณต้องการทริกเกอร์การกระทำเมื่อมีการเปลี่ยนแปลงพารามิเตอร์คุณจะต้องใช้การล็อกซึ่งทำให้สิ่งต่าง ๆ มีความซับซ้อนมากขึ้น
ในการสร้างเธรดคุณจะต้องสร้าง Runnable ของตัวเอง ผ่านพารามิเตอร์ไปยังเธรดในตัวสร้างของคลาสนี้
class MyThread implements Runnable{
private int a;
private String b;
private double c;
public MyThread(int a, String b, double c){
this.a = a;
this.b = b;
this.c = c;
}
public void run(){
doSomething(a, b, c);
}
}
คุณสามารถขยายหรือหรือและให้พารามิเตอร์ตามที่คุณต้องการ มีตัวอย่างที่ง่ายในการที่มีเอกสาร ฉันจะย้ายพวกเขาที่นี่:Thread
class
Runnable
class
class PrimeThread extends Thread {
long minPrime;
PrimeThread(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
PrimeThread p = new PrimeThread(143);
p.start();
class PrimeRun implements Runnable {
long minPrime;
PrimeRun(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
PrimeRun p = new PrimeRun(143);
new Thread(p).start();
ไม่ว่าจะเขียนคลาสที่ใช้ Runnable และส่งผ่านสิ่งที่คุณต้องการใน Constructor ที่กำหนดไว้อย่างเหมาะสมหรือเขียนคลาสที่ขยาย Thread ด้วย Constructor ที่กำหนดไว้อย่างเหมาะสมซึ่งเรียก super () พร้อมพารามิเตอร์ที่เหมาะสม
ในฐานะของ Java 8 คุณสามารถใช้แลมบ์ดาจะจับพารามิเตอร์ที่สุดท้ายได้อย่างมีประสิทธิภาพ ตัวอย่างเช่น:
final String param1 = "First param";
final int param2 = 2;
new Thread(() -> {
// Do whatever you want here: param1 and param2 are in-scope!
System.out.println(param1);
System.out.println(param2);
}).start();
ใน Java 8 คุณสามารถใช้lambda
นิพจน์ด้วยConcurrency API & ExecutorService
แทนระดับที่สูงขึ้นสำหรับการทำงานกับเธรดโดยตรง:
newCachedThreadPool()
สร้างเธรดพูลที่สร้างเธรดใหม่ตามต้องการ แต่จะใช้เธรดที่สร้างขึ้นก่อนหน้านี้ใหม่เมื่อพร้อมใช้งาน กลุ่มเหล่านี้มักจะปรับปรุงประสิทธิภาพของโปรแกรมที่เรียกใช้งานแบบอะซิงโครนัสระยะสั้นจำนวนมาก
private static final ExecutorService executor = Executors.newCachedThreadPool();
executor.submit(() -> {
myFunction(myParam1, myParam2);
});
ฉันรู้ว่าฉันไม่กี่ปีที่ผ่านมา แต่ฉันเจอปัญหานี้และใช้วิธีการนอกรีต ฉันต้องการที่จะทำโดยไม่ต้องเรียนใหม่ดังนั้นนี่คือสิ่งที่ฉันมาด้วย:
int x = 0;
new Thread((new Runnable() {
int x;
public void run() {
// stuff with x and whatever else you want
}
public Runnable pass(int x) {
this.x = x;
return this;
}
}).pass(x)).start();
พารามิเตอร์ที่ส่งผ่านเมธอด start () และ run ():
// Tester
public static void main(String... args) throws Exception {
ThreadType2 t = new ThreadType2(new RunnableType2(){
public void run(Object object) {
System.out.println("Parameter="+object);
}});
t.start("the parameter");
}
// New class 1 of 2
public class ThreadType2 {
final private Thread thread;
private Object objectIn = null;
ThreadType2(final RunnableType2 runnableType2) {
thread = new Thread(new Runnable() {
public void run() {
runnableType2.run(objectIn);
}});
}
public void start(final Object object) {
this.objectIn = object;
thread.start();
}
// If you want to do things like setDaemon(true);
public Thread getThread() {
return thread;
}
}
// New class 2 of 2
public interface RunnableType2 {
public void run(Object object);
}
คุณสามารถสืบทอดคลาสจาก Runnable และระหว่างการก่อสร้าง (พูด) ส่งผ่านพารามิเตอร์ใน
จากนั้นเปิดใช้งานโดยใช้ Thread.start (Runnable r);
หากคุณหมายถึงในขณะที่เธรดกำลังทำงานอยู่ให้ทำการอ้างอิงวัตถุที่คุณได้รับในการเรียกเธรดและเรียกเมธอด setter ที่เหมาะสม (การซิงโครไนซ์ตามความเหมาะสม)
มีวิธีง่ายๆในการส่งพารามิเตอร์ไปยัง runnables รหัส:
public void Function(final type variable) {
Runnable runnable = new Runnable() {
public void run() {
//Code adding here...
}
};
new Thread(runnable).start();
}
ไม่คุณไม่สามารถส่งพารามิเตอร์ไปยังrun()
วิธีการได้ ลายเซ็นจะบอกคุณว่า (ไม่มีพารามิเตอร์) อาจเป็นวิธีที่ง่ายที่สุดในการทำเช่นนี้คือการใช้วัตถุที่สร้างขึ้นโดยมีวัตถุประสงค์เพื่อรับพารามิเตอร์ใน Constructor และเก็บไว้ในตัวแปรสุดท้าย:
public class WorkingTask implements Runnable
{
private final Object toWorkWith;
public WorkingTask(Object workOnMe)
{
toWorkWith = workOnMe;
}
public void run()
{
//do work
}
}
//...
Thread t = new Thread(new WorkingTask(theData));
t.start();
เมื่อคุณทำเช่นนั้น - คุณต้องระวังความสมบูรณ์ของข้อมูลของวัตถุที่คุณส่งผ่านไปยัง 'WorkingTask' ขณะนี้ข้อมูลจะมีอยู่ในสองเธรดที่แตกต่างกันดังนั้นคุณต้องแน่ใจว่าเป็นเธรดที่ปลอดภัย
อีกหนึ่งทางเลือก วิธีนี้ช่วยให้คุณใช้รายการ Runnable เช่นการเรียกใช้ฟังก์ชันอะซิงโครนัส หากงานของคุณไม่จำเป็นต้องส่งคืนผลลัพธ์เช่นดำเนินการบางอย่างโดยที่คุณไม่ต้องกังวลว่าคุณจะ "ส่งผลกลับ" ได้อย่างไร
รูปแบบนี้ช่วยให้คุณสามารถนำไอเท็มกลับมาใช้ใหม่ได้โดยที่คุณต้องการสถานะภายในบางประเภท เมื่อไม่ผ่านพารามิเตอร์ในการดูแลคอนสตรัคเตอร์เป็นสิ่งจำเป็นในการไกล่เกลี่ยโปรแกรมที่เข้าถึงพารามิเตอร์ คุณอาจต้องตรวจสอบเพิ่มเติมว่ากรณีการใช้งานของคุณเกี่ยวข้องกับผู้โทรที่แตกต่างกันหรือไม่เป็นต้น
public class MyRunnable implements Runnable
{
private final Boolean PARAMETER_LOCK = false;
private X parameter;
public MyRunnable(X parameter) {
this.parameter = parameter;
}
public void setParameter( final X newParameter ){
boolean done = false;
synchronize( PARAMETER_LOCK )
{
if( null == parameter )
{
parameter = newParameter;
done = true;
}
}
if( ! done )
{
throw new RuntimeException("MyRunnable - Parameter not cleared." );
}
}
public void clearParameter(){
synchronize( PARAMETER_LOCK )
{
parameter = null;
}
}
public void run() {
X localParameter;
synchronize( PARAMETER_LOCK )
{
localParameter = parameter;
}
if( null != localParameter )
{
clearParameter(); //-- could clear now, or later, or not at all ...
doSomeStuff( localParameter );
}
}
}
เธรด t = เธรดใหม่ (ใหม่ MyRunnable (พารามิเตอร์)); t.start ();
หากคุณต้องการผลลัพธ์ของการประมวลผลคุณจะต้องประสานงานความสมบูรณ์ของ MyRunnable เมื่องานย่อยเสร็จสิ้น คุณสามารถโทรกลับหรือเพียงแค่รอที่หัวข้อ 't' ฯลฯ
สำหรับวัตถุประสงค์ในการโทรกลับฉันมักจะใช้งานทั่วไปของตัวเองRunnable
ด้วยพารามิเตอร์อินพุต:
public interface Runnable<TResult> {
void run(TResult result);
}
การใช้งานง่าย:
myManager.doCallbackOperation(new Runnable<MyResult>() {
@Override
public void run(MyResult result) {
// do something with the result
}
});
ในผู้จัดการ:
public void doCallbackOperation(Runnable<MyResult> runnable) {
new AsyncTask<Void, Void, MyResult>() {
@Override
protected MyResult doInBackground(Void... params) {
// do background operation
return new MyResult(); // return resulting object
}
@Override
protected void onPostExecute(MyResult result) {
// execute runnable passing the result when operation has finished
runnable.run(result);
}
}.execute();
}
สร้างตัวแปรท้องถิ่นในชั้นเรียนของคุณที่หรือextends Thread
implements Runnable
public class Extractor extends Thread {
public String webpage = "";
public Extractor(String w){
webpage = w;
}
public void setWebpage(String l){
webpage = l;
}
@Override
public void run() {// l is link
System.out.println(webpage);
}
public String toString(){
return "Page: "+webpage;
}}
ด้วยวิธีนี้คุณสามารถผ่านตัวแปรเมื่อคุณเรียกใช้
Extractor e = new Extractor("www.google.com");
e.start();
ผลลัพธ์:
"www.google.com"