thread - hilos en java
¿Cómo puedo pasar un parámetro a un subproceso de Java? (17)
¿Puede alguien sugerirme cómo puedo pasar un parámetro a un hilo?
Además, ¿cómo funciona para las clases anónimas?
Especialmente para Android
Para propósitos de devolución de llamada, generalmente implemento mi propio Runnable
genérico con parámetros de entrada:
public interface Runnable<TResult> {
void run(TResult result);
}
El uso es simple:
myManager.doCallbackOperation(new Runnable<MyResult>() {
@Override
public void run(MyResult result) {
// do something with the result
}
});
En gerente:
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();
}
Para clases anónimas:
En respuesta a las ediciones de la pregunta, aquí está cómo funciona para las clases anónimas.
final X parameter = ...; // the final is important
Thread t = new Thread(new Runnable() {
p = parameter;
public void run() {
...
};
t.start();
Clases nombradas:
Tiene una clase que extiende Thread (o implementa Runnable) y un constructor con los parámetros que le gustaría pasar. Luego, cuando creas el nuevo hilo, debes pasar los argumentos y luego iniciar el hilo, algo como esto:
Thread t = new MyThread(args...);
t.start();
Runnable es una solución mucho mejor que Thread BTW. Así que prefiero:
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();
Esta respuesta es básicamente la misma que esta pregunta similar: cómo pasar parámetros a un objeto Thread
A partir de Java 8, puede utilizar un lambda para capturar parámetros que son efectivamente finales . Por ejemplo:
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();
Cree una variable local en su clase que extends Thread
o 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;
}}
De esta manera, puedes pasar una variable cuando la ejecutes.
Extractor e = new Extractor("www.google.com");
e.start();
La salida:
"www.google.com"
Cuando creas un hilo, necesitas una instancia de Runnable
. La forma más fácil de pasar un parámetro sería pasarlo como un argumento al constructor:
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();
Si luego desea cambiar el parámetro mientras el hilo se está ejecutando, simplemente puede agregar un método de establecimiento a su clase ejecutable:
public void setMyParam(String value){
this.myParam = value;
}
Una vez que tenga esto, puede cambiar el valor del parámetro llamando de esta forma:
myRunnable.setMyParam("Goodbye World");
Por supuesto, si desea activar una acción cuando se cambia el parámetro, tendrá que usar bloqueos, lo que hace que las cosas sean mucho más complejas.
Debe pasar el parámetro en el constructor al objeto Ejecutable:
public class MyRunnable implements Runnable {
public MyRunnable(Object parameter) {
// store parameter for later user
}
public void run() {
}
}
Y lo invocamos así:
Runnable r = new MyRunnable(param_value);
new Thread(r).start();
En Java 8 puede usar expresiones lambda
con la API de concurrencia y el servicio de ExecutorService
como un reemplazo de nivel superior para trabajar con subprocesos directamente:
newCachedThreadPool()
Crea un grupo de subprocesos que crea nuevos subprocesos según sea necesario, pero reutilizará los subprocesos construidos previamente cuando estén disponibles. Estos grupos generalmente mejorarán el rendimiento de los programas que ejecutan muchas tareas asíncronas de corta duración.
private static final ExecutorService executor = Executors.newCachedThreadPool();
executor.submit(() -> {
myFunction(myParam1, myParam2);
});
Ver también executors
javadocs .
Escriba una clase que implemente Runnable y pase lo que necesite en un constructor adecuadamente definido, o escriba una clase que extienda Thread con un constructor adecuadamente definido que llame a super () con los parámetros apropiados.
Esta respuesta llega muy tarde, pero tal vez alguien la encuentre útil. Se trata de cómo pasar un parámetro (s) a un Runnable
sin siquiera declarar una clase con nombre (útil para los intérpretes):
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();
Por supuesto, puede posponer la ejecución de start
a un momento más conveniente o apropiado. Y depende de usted cuál será la firma del método init
(por lo que puede tomar más y / o diferentes argumentos) y, por supuesto, incluso su nombre, pero básicamente se obtiene una idea.
De hecho, también hay otra forma de pasar un parámetro a una clase anónima, con el uso de los bloques de inicialización. Considera esto:
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();
Así que todo sucede dentro del bloque inicializador.
Hay una forma sencilla de pasar parámetros a runnables. Código:
public void Function(final type variable) {
Runnable runnable = new Runnable() {
public void run() {
//Code adding here...
}
};
new Thread(runnable).start();
}
No, no puedes pasar parámetros al método run()
. La firma te dice que (no tiene parámetros). Probablemente, la forma más fácil de hacer esto sería usar un objeto especialmente diseñado que toma un parámetro en el constructor y lo almacena en una variable final:
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();
Una vez que haga eso, debe tener cuidado con la integridad de los datos del objeto que pasa a la ''Tarea de trabajo''. Los datos ahora existirán en dos subprocesos diferentes, por lo que debe asegurarse de que sea Thread Safe.
Parámetro que pasa a través de los métodos start () y 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);
}
Para crear un hilo, normalmente creas tu propia implementación de Runnable. Pasa los parámetros al hilo en el constructor de esta clase.
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);
}
}
Puede ampliar la class
Thread
o la class
Runnable
y proporcionar los parámetros que desee. Hay ejemplos simples en los Thread . Los portaré aquí:
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();
Puede derivar una clase de Runnable, y durante la construcción (digamos) pasar el parámetro.
Luego ejecútalo usando Thread.start (Runnable r);
Si quiere decir que mientras se está ejecutando el hilo, simplemente mantenga una referencia a su objeto derivado en el hilo de llamada y llame a los métodos de establecimiento apropiados (sincronizando cuando sea apropiado)
Una opción más; este enfoque le permite utilizar el elemento Ejecutable como una llamada de función asíncrona. Si su tarea no necesita devolver un resultado, por ejemplo, solo realiza alguna acción que no necesita preocuparse por la forma en que devuelve un "resultado".
Este patrón le permite reutilizar un elemento, donde necesita algún tipo de estado interno. Cuando no se pasan parámetros en el cuidado del constructor, es necesario mediar el acceso de los programas a los parámetros. Es posible que necesite más controles si su caso de uso involucra a diferentes personas que llaman, etc.
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 );
}
}
}
Thread t = new Thread (nuevo MyRunnable (parámetro)); t.start ();
Si necesita un resultado del procesamiento, también deberá coordinar la finalización de MyRunnable cuando finalice la subtarea. Puede pasar una llamada o simplemente esperar en el Thread ''t'', etc.
a través del constructor de una clase Runnable o 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();
}