誰かがスレッドにパラメーターを渡す方法を私に提案できますか?
また、匿名クラスではどのように機能しますか?
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という2つのオブジェクトを作成する必要があります。これはパフォーマンス面で悪いと考えられますか?
質問の編集に応じて、匿名のクラスでどのように機能するかを示します。
final X parameter = ...; // the final is important
Thread t = new Thread(new Runnable() {
p = parameter;
public void run() {
...
};
t.start();
Threadを拡張する(またはRunnableを実装する)クラスと、渡すパラメーターを持つコンストラクターがあります。次に、新しいスレッドを作成するときに、引数を渡してから、次のようなスレッドを開始する必要があります。
Thread t = new MyThread(args...);
t.start();
Runnableは、スレッド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
しています。動作しているようです。事前にコピーparameter
しないことで見逃してしまう、微妙なマルチスレッド処理はありp
ますか?
)
最初の例であなたは欠けていると思います
final X parameter
前のnew Runnable()
行がある限り、parameter
内部にアクセスできましたrun()
。余分なことをする必要はありませんでしたp = parameter
。
final
もうそれほど重要ではありません。変数が事実上最終的なものである場合は十分です(それが害を及ぼすことはありません)
Runnableまたは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
、Threadクラスの抽象メソッドをオーバーライドしていることを明示的に述べています。
この答えは非常に遅くなりますが、多分誰かがそれを役に立つでしょう。これは、Runnable
名前付きクラスを宣言することなくパラメーターをに渡す方法についてです(インライナーに便利です)。
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
メソッドのシグネチャを何にするか(したがって、引数の数が増える可能性があります)、そしてもちろんその名前さえもあなた次第ですが、基本的にはアイデアを得ることができます。
実際、初期化ブロックを使用して、匿名クラスにパラメーターを渡す別の方法もあります。このことを考慮:
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();
したがって、すべて初期化ブロック内で発生します。
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();
スレッドの実行中にパラメーターを変更する場合は、実行可能クラスにセッターメソッドを追加するだけです。
public void setMyParam(String value){
this.myParam = value;
}
これを取得したら、次のように呼び出してパラメーターの値を変更できます。
myRunnable.setMyParam("Goodbye World");
もちろん、パラメーターが変更されたときにアクションをトリガーしたい場合は、ロックを使用する必要があるため、状況はかなり複雑になります。
またはのいずれかを拡張し、必要に応じてパラメーターを指定できます。docsに簡単な例があります。ここに移植します: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を実装するクラスを作成し、適切に定義されたコンストラクターで必要なものを渡すか、適切なパラメーターでsuper()を呼び出す適切に定義されたコンストラクターでThreadを拡張するクラスを作成します。
Javaの8では、あなたは使用することができるlambda
との表現を並行処理API&ExecutorService
直接スレッドを扱うためのより高いレベルの代替として:
newCachedThreadPool()
必要に応じて新しいスレッドを作成するスレッドプールを作成しますが、以前に構築されたスレッドが利用可能な場合は再利用します。これらのプールは、通常、短期間の非同期タスクを多数実行するプログラムのパフォーマンスを向上させます。
private static final ExecutorService executor = Executors.newCachedThreadPool();
executor.submit(() -> {
myFunction(myParam1, myParam2);
});
executors
javadocsも参照してください。
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メソッドを呼び出します
いいえ、run()
メソッドにパラメーターを渡すことはできません。シグネチャはそれを通知します(パラメーターはありません)。おそらくこれを行う最も簡単な方法は、コンストラクターでパラメーターを受け取り、それを最終変数に格納する専用オブジェクトを使用することです。
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」に渡すオブジェクトのデータ整合性に注意する必要があります。データは2つの異なるスレッドに存在するようになるので、スレッドセーフであることを確認する必要があります。
さらに1つのオプション。このアプローチでは、非同期関数呼び出しのように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 = new Thread(new MyRunnable(parameter)); 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"