Java 스레드에 매개 변수를 전달하려면 어떻게해야합니까?


290

누구든지 매개 변수를 스레드에 전달하는 방법을 제안 할 수 있습니까?

또한 익명 클래스에서는 어떻게 작동합니까?


5
정확히하려는 것에 대한 추가 설명을 추가 하시겠습니까? 여기에는 여러 가지 기술이 있지만 모두 최종 목표에 달려 있습니다.
Artem Barger

4
이미 실행중인 스레드에 매개 변수를 전달하는 것을 의미합니까? 모든 현재 답변은 매개 변수를 새 스레드에 전달하는 것에 관한
것이므로

이제 사용할 수 있습니다 Consumer<T>.
Alex78191

답변:


371

생성자의 매개 변수를 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();

7
@jasonm 아니오, 생성자입니다-생성자에는 반환 유형이 없습니다.
Alnitak

즉, 사용하여 생성 된 각 스레드 r는 동일한 인수를 가지므로 실행중인 여러 스레드에 다른 인수를 전달 MyThread하려면 MyThread각 스레드에 대해 원하는 인수를 사용하여 새 인스턴스 를 만들어야합니다 . 다시 말해, 스레드를 시작하고 실행하려면 Thread와 MyThread라는 두 개의 개체를 만들어야합니다. 이것이 성능 측면에서 나쁜 것으로 간주됩니까?
Isaac Kleinman

2
@IsaacKleinman은 Thread를 확장하지 않는 한 어쨌든 그렇게해야합니다. 이 경우에도이 솔루션은 여전히 ​​작동합니다. "Runnable 구현"을 "Extents Thread", "Runnable"을 "Thread", "new Thread (r)"를 "r"로 변경하면됩니다.
user253751

111

익명 클래스의 경우 :

질문 편집에 대한 응답으로 익명 클래스에서 작동하는 방식은 다음과 같습니다.

   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은 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 객체에 매개 변수를 전달하는 방법


2
필드를 전혀 사용하지 않고 메소드 parameter에서 직접 액세스한다는 점을 제외하고는 익명 클래스 예제와 유사한 코드가 있습니다 . 작동하는 것 같습니다. 내가 복사하지 않음으로써 실종 미묘한 멀티 스레딩 일이 있는가 하는 사전은? run()pparameterp
랜달 쿡

나는 당신이 )첫 번째 예제에서 빠진 것 같아요
Hack-R

익명 클래스의 @RandallCook과 동일한 경험을했습니다. 만큼 내가 있었다으로 final X parameter전과 new Runnable()라인, 그때에 액세스 할 수 parameter내부 run(). 나는 여분의 일을 할 필요가 없었습니다 p = parameter.
wisbucky

final더 이상 그렇게 중요하지 않습니다. 변수가 효과적으로 최종적 이면 충분합니다 (유해하지는 않지만)
user85421

43

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();
}

5
Runnable을 구현하는 대신 Thread를 확장하는 방법을 보여주는 +1
Caelum

1
왜 우리 @Override에게 필요한가?

@ Snow는 @OverrideThread 클래스의 추상 메서드를 재정의하고 있다고 명시 적으로 설명합니다.
wyskoj 2016 년

22

이 답변은 매우 늦었지만 누군가 유용 할 것입니다. 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();

모든 것은 초기화 블록 내부에서 발생합니다.


나는 실제로이 마지막 예를 아주 좋아했습니다. JS에서 클로저를 사용하여 외부 범위의 변수를 참조하는 것을 상기시킵니다. 그러나 this.myParam그때 정말로 필요합니까? 개인 변수를 삭제하고 외부 범위에서 변수를 참조 할 수 없습니까? 물론 스레드를 시작한 후 변수가 열려 열려있는 것과 같은 의미가 있음을 이해합니다.
oligofren

@JeffG는 실제로 아래 답변에서 이것을 대답했습니다!
oligofren

17

스레드를 만들 때의 인스턴스가 필요합니다 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");

물론 매개 변수가 변경 될 때 작업을 트리거하려면 잠금을 사용해야하므로 상황이 훨씬 복잡해집니다.


1
세터를 추가해도 잠재적 인 경쟁 조건이 발생하지 않습니까? 스레드가 변수를 하나의 값으로 시작하지만 세터가 실행 중 변경하면 문제가되지 않습니까?
anon58192932

사실, 설정자와 매개 변수에 대한 모든 액세스는 동기화되어야합니다.
jwoolard

9

스레드를 만들려면 일반적으로 자신 만의 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);
   }
}

8

당신이 중 하나를 확장 할 수 있습니다 또는를 원하는대로 매개 변수를 제공합니다. 문서 에는 간단한 예제가 있습니다 . 여기에 포트하겠습니다 :Thread classRunnable 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();

7

Runnable을 구현하는 클래스를 작성하고 적절하게 정의 된 생성자에 필요한 것을 전달하거나 적절한 매개 변수를 사용하여 super ()를 호출하는 적절하게 정의 된 생성자로 Thread를 확장하는 클래스를 작성하십시오.


6

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();

5

자바 8에서는 사용할 수 lambda와 표현 동시성 API &을 ExecutorService직접 스레드 작업을위한 높은 수준의 대체 :

newCachedThreadPool()필요에 따라 새 스레드를 작성하는 스레드 풀을 작성하지만 사용 가능한 경우 이전에 구성된 스레드를 재사용합니다. 이러한 풀은 일반적으로 많은 단기 비동기 작업을 실행하는 프로그램의 성능을 향상시킵니다.

    private static final ExecutorService executor = Executors.newCachedThreadPool();

    executor.submit(() -> {
        myFunction(myParam1, myParam2);
    });

executors javadocs 도 참조하십시오 .


마지막으로 그 성가신 분야없이 그것을 할 수있는 방법. 지금은 단지 자바 8로 업그레이드 내 제품 기다릴 필요
스리 Sarnobat에게

5

나는 몇 년 늦었다는 것을 알고 있지만이 문제를 겪고 정통 접근 방식을 취했습니다. 나는 새로운 수업을 만들지 않고 그것을하고 싶었으므로 이것이 내가 생각해 낸 것입니다.

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();

4

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);
}

3

Runnable에서 클래스를 파생시킬 수 있으며 생성하는 동안 매개 변수를 전달할 수 있습니다.

그런 다음 Thread.start (Runnable r);

스레드가 실행 중임 을 의미 하는 경우 호출 스레드에서 파생 객체에 대한 참조를 보유하고 적절한 setter 메소드를 호출하십시오 (적절한 경우 동기화)


2

런너 블에 파라미터를 전달하는 간단한 방법이 있습니다. 암호:

public void Function(final type variable) {
    Runnable runnable = new Runnable() {
        public void run() {
            //Code adding here...
        }
    };
    new Thread(runnable).start();
}

2

아니요 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'에 전달하는 객체의 데이터 무결성에주의해야합니다. 데이터는 이제 두 개의 다른 스레드에 존재하므로 스레드 안전인지 확인해야합니다.


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 MyRunnable (parameter)); t.start ();

처리 결과가 필요한 경우 하위 작업이 완료 될 때 MyRunnable 완료를 조정해야합니다. 전화를 다시 받거나 Thread 't'등을 기다릴 수 있습니다.


1

특히 Android 용

콜백을 위해 일반적 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();
}

1

클래스에서 지역 변수를 만들 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"
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.