Adakah yang bisa menyarankan saya bagaimana saya bisa mengirimkan parameter ke utas?
Juga, bagaimana cara kerjanya untuk kelas anonim?
Consumer<T>
.
Adakah yang bisa menyarankan saya bagaimana saya bisa mengirimkan parameter ke utas?
Juga, bagaimana cara kerjanya untuk kelas anonim?
Consumer<T>
.
Jawaban:
Anda perlu meneruskan parameter dalam konstruktor ke objek Runnable:
public class MyRunnable implements Runnable {
public MyRunnable(Object parameter) {
// store parameter for later user
}
public void run() {
}
}
dan memohon demikian:
Runnable r = new MyRunnable(param_value);
new Thread(r).start();
r
akan memiliki argumen yang sama, jadi jika kita ingin memberikan argumen berbeda ke beberapa Thread yang sedang berjalan, MyThread
kita perlu membuat MyThread
instance baru menggunakan argumen yang diinginkan untuk setiap Thread. Dengan kata lain, untuk mendapatkan thread dan menjalankan kita perlu membuat dua objek: Thread dan MyThread. Apakah ini dianggap buruk, bijaksana?
Menanggapi suntingan pertanyaan di sini adalah cara kerjanya untuk kelas Anonim
final X parameter = ...; // the final is important
Thread t = new Thread(new Runnable() {
p = parameter;
public void run() {
...
};
t.start();
Anda memiliki kelas yang memperluas Thread (atau mengimplementasikan Runnable) dan konstruktor dengan parameter yang ingin Anda sampaikan. Kemudian, ketika Anda membuat utas baru, Anda harus memberikan argumen, dan kemudian memulai utas, sesuatu seperti ini:
Thread t = new MyThread(args...);
t.start();
Runnable adalah solusi yang jauh lebih baik daripada Thread BTW. Jadi saya lebih suka:
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();
Jawaban ini pada dasarnya sama dengan pertanyaan serupa ini: Cara meneruskan parameter ke objek Thread
parameter
langsung dari run()
metode tanpa menggunakan bidang seperti p
sama sekali. Sepertinya berhasil. Apakah ada beberapa hal multithreading halus yang saya lewatkan dengan tidak menyalin parameter
ke p
sebelumnya?
)
dalam contoh pertama
final X parameter
sebelum new Runnable()
baris, maka saya bisa mengakses parameter
di dalam run()
. Saya tidak perlu melakukan ekstra p = parameter
.
final
tidak begitu penting lagi; itu sudah cukup jika variabel efektif final (meskipun tidak ada salahnya)
melalui konstruktor dari kelas Runnable atau Thread
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
secara eksplisit menyatakan bahwa itu menimpa metode abstrak di kelas Thread.
Jawaban ini datang sangat terlambat, tetapi mungkin seseorang akan menemukannya berguna. Ini adalah tentang cara meneruskan parameter ke kelas Runnable
tanpa mendeklarasikan kelas bernama (berguna untuk inliner):
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();
Tentu saja Anda dapat menunda eksekusi start
ke momen yang lebih nyaman atau tepat. Dan terserah Anda apa yang akan menjadi tanda tangan init
metode (sehingga mungkin diperlukan lebih banyak dan / atau argumen yang berbeda) dan tentu saja bahkan namanya, tetapi pada dasarnya Anda mendapatkan ide.
Bahkan ada juga cara lain untuk mengirimkan parameter ke kelas anonim, dengan menggunakan blok initializer. Pertimbangkan ini:
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();
Jadi semua terjadi di dalam blok initializer.
this.myParam
itu benar-benar diperlukan? Tidak bisakah Anda hanya menjatuhkan variabel pribadi dan merujuk ke variabel dari lingkup luar? Saya mengerti (tentu saja) bahwa ini memiliki beberapa implikasi, seperti variabel yang terbuka untuk diubah setelah memulai utas.
Saat Anda membuat utas, Anda membutuhkan instance dari Runnable
. Cara termudah untuk mengirimkan parameter adalah dengan mengirimkannya sebagai argumen ke konstruktor:
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();
Jika kemudian Anda ingin mengubah parameter saat utas berjalan, Anda bisa menambahkan metode setter ke kelas runnable Anda:
public void setMyParam(String value){
this.myParam = value;
}
Setelah ini, Anda dapat mengubah nilai parameter dengan memanggil seperti ini:
myRunnable.setMyParam("Goodbye World");
Tentu saja, jika Anda ingin memicu aksi ketika parameter diubah, Anda harus menggunakan kunci, yang membuat segalanya menjadi lebih kompleks.
Untuk membuat utas, Anda biasanya membuat implementasi Runnable Anda sendiri. Lewati parameter ke utas di konstruktor kelas ini.
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);
}
}
Anda dapat memperpanjang atau dan menyediakan parameter yang Anda inginkan. Ada contoh sederhana dalam dokumen . Saya akan port mereka di sini: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();
Baik tulis kelas yang mengimplementasikan Runnable, dan berikan apa pun yang Anda butuhkan di konstruktor yang didefinisikan dengan tepat, atau tulis kelas yang memperluas Thread dengan konstruktor yang didefinisikan dengan tepat yang memanggil super () dengan parameter yang sesuai.
Pada Java 8, Anda dapat menggunakan lambda untuk menangkap parameter yang final secara efektif . Sebagai contoh:
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();
Di Java 8 Anda dapat menggunakan lambda
ekspresi dengan Concurrency API & ExecutorService
sebagai pengganti tingkat yang lebih tinggi untuk bekerja dengan utas secara langsung:
newCachedThreadPool()
Membuat kumpulan utas yang membuat utas baru sesuai kebutuhan, tetapi akan menggunakan ulang utas yang sebelumnya dibuat saat tersedia. Kumpulan ini biasanya akan meningkatkan kinerja program yang menjalankan banyak tugas asinkron yang berumur pendek.
private static final ExecutorService executor = Executors.newCachedThreadPool();
executor.submit(() -> {
myFunction(myParam1, myParam2);
});
Lihat juga executors
javadocs .
Saya tahu bahwa saya terlambat beberapa tahun, tetapi saya menemukan masalah ini dan mengambil pendekatan yang tidak ortodoks. Saya ingin melakukannya tanpa membuat kelas baru, jadi inilah yang saya buat:
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();
Melewati parameter melalui metode start () dan 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);
}
Anda bisa mendapatkan kelas dari Runnable, dan selama konstruksi (katakanlah) masukkan parameter.
Kemudian jalankan menggunakan Thread.start (Runnable r);
Jika Anda berarti sementara benang sedang berjalan, maka hanya memegang referensi ke objek Anda berasal di thread memanggil, dan memanggil metode setter yang tepat (sinkronisasi mana yang sesuai)
Tidak, Anda tidak dapat meneruskan parameter ke run()
metode. Tanda tangan memberi tahu Anda (tidak memiliki parameter). Mungkin cara termudah untuk melakukan ini adalah dengan menggunakan objek yang dibangun dengan tujuan yang mengambil parameter dalam konstruktor dan menyimpannya dalam variabel akhir:
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();
Setelah Anda melakukannya - Anda harus berhati-hati dengan integritas data objek yang Anda berikan ke 'WorkingTask'. Data sekarang akan ada di dua utas berbeda sehingga Anda harus memastikan itu adalah Utas Aman.
Satu opsi lebih lanjut; pendekatan ini memungkinkan Anda menggunakan item Runnable seperti panggilan fungsi tidak sinkron. Jika tugas Anda tidak perlu mengembalikan hasil, misalnya hanya melakukan beberapa tindakan Anda tidak perlu khawatir tentang bagaimana Anda mengembalikan "hasil".
Pola ini memungkinkan Anda menggunakan kembali suatu item, di mana Anda memerlukan semacam kondisi internal. Ketika tidak melewati parameter dalam perawatan konstruktor diperlukan untuk memediasi akses program ke parameter. Anda mungkin perlu lebih banyak memeriksa jika kasus penggunaan Anda melibatkan penelepon yang berbeda, dll.
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 );
}
}
}
Utas t = Utas baru (MyRunnable baru (parameter)); t.start ();
Jika Anda membutuhkan hasil pemrosesan, Anda juga perlu mengoordinasikan penyelesaian MyRunnable ketika sub-tugas selesai. Anda bisa menjawab panggilan kembali atau hanya menunggu di Thread 't', dll.
Untuk tujuan panggilan balik, saya biasanya menerapkan generik sendiri Runnable
dengan parameter input:
public interface Runnable<TResult> {
void run(TResult result);
}
Penggunaannya sederhana:
myManager.doCallbackOperation(new Runnable<MyResult>() {
@Override
public void run(MyResult result) {
// do something with the result
}
});
Dalam manajer:
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();
}
Buat variabel lokal di kelas Anda yang extends Thread
atau 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;
}}
Dengan cara ini, Anda bisa melewatkan variabel saat Anda menjalankannya.
Extractor e = new Extractor("www.google.com");
e.start();
Hasil:
"www.google.com"