java example "구현 자바 Runnable"대 "확장 스레드"자바




java multithreading example (24)

자바에서 쓰레드를 몇시 동안 보냈는지, 다음 두 가지 방법으로 쓰레드를 작성했다.

implements Runnable 사용하여 implements Runnable :

public class MyRunnable implements Runnable {
    public void run() {
        //Code
    }
}
//Started with a "new Thread(new MyRunnable()).start()" call

또는, extends Thread :

public class MyThread extends Thread {
    public MyThread() {
        super("MyThread");
    }
    public void run() {
        //Code
    }
}
//Started with a "new MyThread().start()" call

이 두 코드 블록에 중요한 차이가 있습니까?


나는 전문가는 아니지만, 확장 대신 Runnable을 구현하는 이유 중 하나를 생각해 볼 수 있습니다. Java는 단일 상속 만 지원하므로 하나의 클래스 만 확장 할 수 있습니다.

편집 : 이것은 원래 "구현 인터페이스가 적은 자원을 필요로했다." 뿐만 아니라 새로운 Thread 인스턴스를 생성해야하기 때문에 잘못되었다.


음, 이렇게 많은 답변을 추가하겠습니다. 이것은 Extending v/s Implementing Thread 를 이해하는데 도움이 될 것입니다.
Extends는 두 클래스 파일을 매우 가깝게 묶어 주며 코드를 다루기가 힘들 수 있습니다.

두 방법 모두 동일한 일을하지만 몇 가지 차이점이 있습니다.
가장 일반적인 차이점은

  1. Thread 클래스를 확장하면 그 후에는 필요한 다른 클래스를 확장 할 수 없습니다. (아시다시피 Java는 둘 이상의 클래스를 상속 할 수 없습니다.
  2. 당신이 Runnable을 구현할 때, 당신은 미래에 또는 다른 어떤 클래스를 확장하기위한 공간을 저장할 수 있습니다.

그러나 Runnable과 확장 Thread를 구현하는 것의 중요한 차이점
by extending Thread, each of your threads has a unique object associated with it, whereas implementing Runnable, many threads can share the same object instance.

다음 예제는보다 명확하게 이해하는 데 도움이됩니다.

//Implement Runnable Interface...
 class ImplementsRunnable implements Runnable {

private int counter = 0;

public void run() {
    counter++;
    System.out.println("ImplementsRunnable : Counter : " + counter);
 }
}

//Extend Thread class...
class ExtendsThread extends Thread {

private int counter = 0;

public void run() {
    counter++;
    System.out.println("ExtendsThread : Counter : " + counter);
 }
}

//Use above classes here in main to understand the differences more clearly...
public class ThreadVsRunnable {

public static void main(String args[]) throws Exception {
    // Multiple threads share the same object.
    ImplementsRunnable rc = new ImplementsRunnable();
    Thread t1 = new Thread(rc);
    t1.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    Thread t2 = new Thread(rc);
    t2.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    Thread t3 = new Thread(rc);
    t3.start();

    // Creating new instance for every thread access.
    ExtendsThread tc1 = new ExtendsThread();
    tc1.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    ExtendsThread tc2 = new ExtendsThread();
    tc2.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    ExtendsThread tc3 = new ExtendsThread();
    tc3.start();
 }
}

위의 프로그램의 출력.

ImplementsRunnable : Counter : 1
ImplementsRunnable : Counter : 2
ImplementsRunnable : Counter : 3
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1

Runnable 인터페이스 접근 방식에서는 하나의 클래스 인스턴스 만 만들어지고 다른 스레드에서 공유됩니다. 카운터의 값은 각 스레드 액세스마다 증가합니다.

반면에 Thread 클래스 접근 방식에서는 모든 스레드 액세스에 대해 별도의 인스턴스를 만들어야합니다. 따라서 각 클래스 인스턴스에 대해 서로 다른 메모리가 할당되고 각각 별도의 카운터가 있으므로 값은 동일하게 유지되므로 개체 참조가 동일하지 않기 때문에 증분이 발생하지 않습니다.

Runnable을 언제 사용합니까?
스레드 그룹에서 동일한 자원에 액세스하려면 Runnable 인터페이스를 사용하십시오. 여러 객체 생성이 더 많은 메모리를 소비하고 큰 성능 오버 헤드가되기 때문에 여기서 Thread 클래스를 사용하지 마십시오.

Runnable을 구현하는 클래스는 스레드가 아니며 단지 클래스입니다. Runnable이 Thread가 되려면, Thread의 인스턴스를 생성하고 그 자체를 타겟으로 전달해야한다.

run() 메소드와 다른 Thread 메소드를 오버라이드 run() override)하는 것을 계획하고있는 경우, 대부분의 경우, Runnable 인터페이스를 사용할 필요가 있습니다. 프로그래머가 클래스의 기본 동작을 수정하거나 향상 시키려하지 않는 한 클래스가 서브 클래 싱되지 않아야하기 때문에 이것은 중요합니다.

슈퍼 클래스를 확장 할 필요가있는 경우, Thread 클래스를 사용하는 것보다 Runnable 인터페이스를 구현하는 것이 더 적절합니다. Runnable 인터페이스를 구현하면서 다른 클래스를 확장하여 스레드를 만들 수 있기 때문입니다.

이게 도움이되기를 바랍니다!


tl; dr : implements Runnable이 더 좋습니다. 그러나주의 사항은 중요합니다.

일반적으로 Thread 보다는 Runnable 과 같은 것을 사용하는 것이 좋습니다. 왜냐하면 당신의 작업을 당신의 선택과 느슨하게 결합 할 수 있기 때문입니다. 예를 들어, Runnable 을 사용하고 나중에 실제로 Thread 필요하지 않다는 것을 결정한 경우에는 threadA.run ()을 호출하면됩니다.

주의 사항 : 여기서는 원시 스레드를 사용하지 않는 것이 좋습니다. 나는 CallablesFutureTasks 의 사용을 선호한다. (javadoc에서 : "취소 가능한 비동기 계산"). 시간 제한, 적절한 취소 및 현대 동시성 지원의 스레드 풀링은 모두 원시 스레드 더미보다 훨씬 유용합니다.

Follow-up : Runnables를 사용할 수있게 해주는 FutureTask 생성자 가 있습니다 (가장 편한 것이면). 그리고 여전히 동시성 도구의 이점을 얻으실 수 있습니다. javadoc의 인용문 :

특정 결과가 필요하지 않은 경우 다음 형식의 구문을 사용하는 것이 좋습니다.

Future<?> f = new FutureTask<Object>(runnable, null)

따라서 우리가 runnablethreadA 대체하면 다음과 같이됩니다.

new FutureTask<Object>(threadA, null)

Runnables에 더 가깝게 머무를 수있는 또 다른 옵션은 ThreadPoolExecutor 입니다. execute 메소드를 사용해, Runnable를 건네 주어 「장래에 지정된 태스크」를 실행할 수 있습니다.

스레드 풀을 사용하려는 경우 위 코드는 Executors.newCachedThreadPool() 팩터 리 메소드를 사용하여 다음과 같이됩니다.

ExecutorService es = Executors.newCachedThreadPool();
es.execute(new ThreadA());

내가 틀리지 않다면, 그것은 다소 비슷합니다.

인터페이스와 추상 클래스의 차이점은 무엇입니까?

extends Islations " Is A "릴레이션 & 인터페이스는 " Has a "기능을 제공합니다.

구현을 선호한다. Runnable :

  1. Thread 클래스를 확장하고 Thread API 기본 구현을 수정할 필요가없는 경우
  2. 화재 및 명령을 실행하는 경우
  3. 이미 다른 수업을 연장하고있는 경우

선호하는 " 확장 스레드 ":

  1. 오라클 문서 페이지에 나열된 것처럼 이러한 Thread 메소드 중 하나를 대체해야하는 경우

일반적으로 스레드 동작을 재정의 할 필요는 없습니다. 그래서 Runnable 은 대부분의 시간 동안 선호된다.

다른 메모에서 고급 ExecutorService또는 ThreadPoolExecutorServiceAPI를 사용하면 더 많은 유연성과 제어 기능을 제공합니다.

이 SE 질문을보십시오 :

ExecutorService 대 캐주얼 스레드 Spawner


예 : Runnable 구현하는 것이 IMO를 구현하는 기본 방법입니다. 당신은 정말로 스레드의 동작을 전문적으로 다루지 않습니다. 너는 달릴 무언가를주고있다. 즉, composition철학적으로 "순수한"방법입니다.

실용적인 측면에서 보면 Runnable 을 구현하고 다른 클래스에서도 확장 할 수 있음을 의미합니다.


Runnable을 구현하는 것과 Thread를 확장하는 것의 한 가지 차이점은 Thread를 확장함으로써 각 스레드가 관련된 고유 객체를 가지지 만 Runnable을 구현하면 많은 스레드가 동일한 객체 인스턴스를 공유 할 수 있다는 것입니다.

Runnable을 구현하는 클래스는 스레드가 아니며 단지 클래스입니다. thread에 의해 Runnable가 실행되도록 (듯이)하려면, Thread의 인스턴스를 작성해, Runnable의 인스턴스를 타겟으로서 건네 줄 필요가 있습니다.

Run () 메소드와 다른 Thread 메소드를 오버라이드 (override)하는 것을 계획하고있는 경우, 대부분의 경우, Runnable 인터페이스를 사용할 필요가 있습니다. 프로그래머가 클래스의 기본 동작을 수정하거나 향상 시키려하지 않는 한 클래스가 서브 클래 싱되지 않아야하기 때문에 이것은 중요합니다.

슈퍼 클래스를 확장 할 필요가있는 경우, Thread 클래스를 사용하는 것보다 Runnable 인터페이스를 구현하는 것이 더 적절합니다. Runnable 인터페이스를 구현하면서 다른 클래스를 확장하여 스레드를 만들 수 있기 때문입니다. 그러나 Thread 클래스를 확장하면 다른 클래스에서 상속받을 수 없습니다.


나는 세 번째 방법이 있다고 말할 것이다 :

public class Something {

    public void justAnotherMethod() { ... }

}

new Thread(new Runnable() {
   public void run() {
    instanceOfSomething.justAnotherMethod();
   }
}).start();

어쩌면이 최근 Javascript 및 Actionscript 3 최근 사용량에 의해 조금 영향을받습니다 있지만이 방법은 클래스 Runnable 꽤 모호한 인터페이스를 구현할 필요가 없습니다.


여기에 두 개의 센트를 추가하십시오 . 항상 가능한 한 항상 사용하십시오 implements Runnable. 다음은 extends Threads를 사용하지 말아야하는 이유에 대한 두 가지주의 사항입니다.

  1. Thread 클래스를 결코 확장하지 않는 것이 이상적입니다. Thread클래스해야한다 final. 적어도 그 방법은 좋아 thread.getId(). s 확장과 관련된 버그는 this 토론을 참조하십시오 Thread.

  2. 퍼즐을 풀고 자하는 사람들은 Thread를 확장하는 또 다른 부작용을 발견 할 수 있습니다. 아무도 알려주지 않으면 아래 코드는 도달 할 수없는 코드를 출력합니다.

http://pastebin.com/BjKNNs2G 참조 http://pastebin.com/BjKNNs2G .

public class WaitPuzzle {

    public static void main(String[] args) throws InterruptedException {
        DoNothing doNothing = new DoNothing();
        new WaitForever(doNothing).start();
        new WaitForever(doNothing).start();
        new WaitForever(doNothing).start();
        Thread.sleep(100);
        doNothing.start();
        while(true) {
            Thread.sleep(10);
        }
    }


    static class WaitForever extends  Thread {

        private DoNothing doNothing;

        public WaitForever(DoNothing doNothing) {
            this.doNothing =  doNothing;
        }

        @Override
        public void run() {
            synchronized (doNothing) {
                try {
                    doNothing.wait(); // will wait forever here as nobody notifies here
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Unreachable Code");
            }
        }
    }

    static class DoNothing extends Thread {

        @Override
        public void run() {
            System.out.println("Do Nothing ");
        }
    } 
}

Extending Thread와 Runnable 구현의 차이점은 다음과 같습니다.


여기있는 모든 사람들은 Runnable을 구현하는 것이 갈 길이라고 생각하는 것 같지만, 실제로는 동의하지 않지만 내 의견으로는 Thread를 확장하는 경우도 있습니다. 실제로는 코드에서 일종의 시연을해야합니다.

Runnable를 구현하면 Runnable을 구현하는 클래스는 스레드 이름을 제어 할 수 없으며 스레드 이름을 설정할 수있는 호출 코드는 다음과 같습니다.

new Thread(myRunnable,"WhateverNameiFeelLike");

하지만 스레드를 확장하면 클래스 자체에서이를 관리하게됩니다 (예를 들어 스레드 'ThreadB'의 이름을 지정하는 것과 같습니다). 이 경우 귀하는 :

A)는 디버깅 목적으로 더 유용한 이름을 줄 수 있습니다

B)는 해당 클래스의 모든 인스턴스에 해당 이름을 사용하도록 강요합니다 (스레드라는 사실을 무시하고 Runnable 인 것처럼 위의 작업을 수행하지 않는 한). 그러나 어떤 경우이든 여기에서 대회에 관해 이야기하고 있습니다. 내가 느낀 그 가능성을 무시하십시오).

예를 들어, 생성 된 스택 추적을 가져 와서 스레드 이름으로 사용할 수도 있습니다. 이것은 이상하게 보일 수 있지만 코드가 어떻게 구성되어 있는지에 따라 디버깅 목적으로 매우 유용 할 수 있습니다.

이것은 작은 것처럼 보일지도 모르지만 많은 스레드를 가진 매우 복잡한 응용 프로그램을 가지고 갑자기 모든 것이 갑자기 멈추었습니다 (교착 상태 또는 네트워크 프로토콜의 결함으로 인해 명백한 - 또는 다른 끝이없는 이유) 그때 모든 스레드가 'Thread-1', 'Thread-2', 'Thread-3'이라고 불리는 Java에서 스택 덤프를 얻는 것은 항상 유용하지는 않습니다 (스레드가 구조화 된 것, 그리고 스택 추적에 의해 어느 것인가를 유용하게 알 수 있는지 여부 - 항상 동일한 코드를 실행하는 여러 스레드 그룹을 사용하는 경우에는 항상 가능하지는 않음).

물론 당신은 또한 생성 호출의 스택 트레이스에 이름을 설정하고 표준 자바 스레드 클래스 대신 Runnable 구현물과 함께 사용하는 스레드 클래스의 확장을 생성함으로써 일반적인 방법으로 위의 작업을 수행 할 수 있다고 말했 더라. (아래 참조)하지만 스택 추적 외에도 디버깅을위한 스레드 이름에 유용한 컨텍스트 관련 정보가 더 많을 수 있습니다 (처리 할 수있는 많은 대기열 또는 소켓 중 하나에 대한 참조). 특정 스레드 (예 : 대기열 / 소켓)에서 컴파일러가 특정 정보 (예 : 대기열 / 소켓)를 사용하도록 강제 할 수 있도록 스레드를 특별히 확장합니다.

다음은 이름으로 호출 스택 추적이있는 일반 스레드의 예입니다.

public class DebuggableThread extends Thread {
    private static String getStackTrace(String name) {
        Throwable t= new Throwable("DebuggableThread-"+name);
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        PrintStream ps = new PrintStream(os);
        t.printStackTrace(ps);
        return os.toString();
    }

    public DebuggableThread(String name) {
        super(getStackTrace(name));
    }

    public static void main(String[] args) throws Exception {
        System.out.println(new Thread());
        System.out.println(new DebuggableThread("MainTest"));
    }
}

다음은 두 이름을 비교 한 출력 샘플입니다.

Thread[Thread-1,5,main]
Thread[java.lang.Throwable: DebuggableThread-MainTest
    at DebuggableThread.getStackTrace(DebuggableThread.java:6)
    at DebuggableThread.<init>(DebuggableThread.java:14)
    at DebuggableThread.main(DebuggableThread.java:19)
,5,main]

이 내용은 Oracle의 Thread 정의 및 시작 자습서에서 설명합니다.

다음 중이 관용구 중 어느 것을 사용해야합니까? Runnable 객체를 사용하는 첫 번째 관용구는보다 일반적입니다. 왜냐하면 Runnable 객체가 Thread가 아닌 다른 클래스를 서브 클래스화할 수 있기 때문입니다. 두 번째 관용구는 간단한 응용 프로그램에서 사용하기가 더 쉽지만 작업 클래스가 Thread의 자손이어야한다는 사실로 인해 제한됩니다. 이 과정에서는 Runnable 작업과 해당 작업을 실행하는 Thread 개체를 구분하는 첫 번째 방법에 중점을 둡니다. 이 접근법은보다 유연 할뿐만 아니라 나중에 다루는 고급 스레드 관리 API에도 적용됩니다.

즉, 구현 Runnable은 클래스가 다른 클래스를 확장하는 시나리오에서 작동합니다 Thread. Java는 다중 상속을 지원하지 않습니다. 또한 Thread일부 고급 스레드 관리 API를 사용할 때는 확장 이 불가능합니다. 확장 Thread이 바람직한 유일한 시나리오 는 앞으로 업데이트가 적용되지 않는 작은 응용 프로그램에 있습니다. Runnable프로젝트가 성장함에 따라 유연 해지기 때문에 거의 항상 구현 하는 것이 좋습니다 . 자바에서 많은 인터페이스를 구현할 수 있기 때문에 디자인 변경에 큰 영향은 없지만 하나의 클래스 만 확장하십시오.


runnable을 사용하면 다른 클래스로 확장 할 수있는 공간을 절약 할 수 있습니다.


실제로 RunnableThread 를 서로 비교하는 것은 현명한 방법이 아닙니다.

이 두 가지는 자동차의 Wheel and Engine 관계처럼 멀티 스레딩에서 의존성과 관계가 있습니다.

나는 두 단계의 멀티 스레딩을위한 유일한 방법이 있다고 말합니다. 내 요점을 말해 보자.

실행 파일 :
interface Runnable 구현할 때 다른 스레드에서 run able 있는 무언가를 생성한다는 것을 의미합니다. 이제 스레드 (스레드 내에서 실행 가능) 내에서 실행할 수있는 무언가를 만드는 것이 스레드를 만드는 것을 의미하지 않습니다.
따라서 MyRunnable 클래스는 void run 메소드가있는 일반적인 클래스 MyRunnable 입니다. 그리고 객체는 호출 될 때 정상적으로 run 되는 메서드 run 만있는 일반 객체입니다. (스레드에서 객체를 전달하지 않는 한).

실:
class Thread , start() 메소드를 통해 멀티 스레딩을 실제로 가능하게하는 새로운 Thread를 시작할 수있는 매우 특별한 클래스라고 할 수 있습니다.

비교하는 것이 현명하지 않은 이유는 무엇입니까?
멀티 스레딩을 위해 둘 다 필요하기 때문입니다.

멀티 스레딩의 경우 두 가지가 필요합니다.

  • 스레드 (Runnable) 내에서 실행할 수있는 것.
  • 뭔가 새로운 스레드 (스레드)를 시작할 수 있습니다.

그래서 기술적으로나 이론적으로 모두 스레드를 시작하는 데 필요합니다. 하나는 실행 되고 하나는 실행하게됩니다 ( Wheel and EngineWheel and Engine 처럼).

그래서 MyRunnable 을 스레드 인스턴스에 전달해야하는 스레드를 시작할 수 없습니다.

그러나 클래스 ThreadRunnable 구현하기 때문에 class Thread 사용하여 스레드를 생성하고 실행할 수 있습니다. 그래서 우리 모두는 Thread 또한 Runnable 내부에 있다는 것을 알고 있습니다.

마지막으로 ThreadRunnable 은 경쟁자 나 교체가 아닌 멀티 스레딩을 위해 서로를 보완합니다.


Java는 다중 상속을 지원하지 않으므로 Thread 클래스를 확장하면 다른 클래스는 확장되지 않습니다.

예 : 애플릿을 작성하는 경우 Applet 클래스를 확장해야하므로 여기서 스레드를 작성하는 유일한 방법은 Runnable 인터페이스를 구현하는 것입니다.


기본 클래스를 확장하는 대신 인터페이스를 구현하려는 한 가지 이유는 이미 다른 클래스를 확장하고 있다는 것입니다. 하나의 클래스 만 확장 할 수 있지만 원하는 수의 인터페이스를 구현할 수 있습니다.

Thread를 확장하면 기본적으로 'this'가 아닌 다른 스레드가 논리를 실행할 수 없습니다. 만약 당신이 단지 당신의 로직을 실행 하는 스레드를 원한다면 Runnable을 구현하는 것이 낫다.


다른 클래스를 구현하거나 확장하고 싶다면 다른 클래스를 확장하거나 구현하지 않으려면 Runnable 인터페이스가 가장 좋습니다. Thread 클래스가 바람직합니다.

가장 일반적인 차이점은

extends Thread 클래스를 extends Thread 하면 그 후에는 필요한 다른 클래스를 확장 할 수 없습니다. (아시다시피 Java는 둘 이상의 클래스를 상속 할 수 없습니다.

당신이 implements Runnableimplements Runnable 때, 당신은 미래에 또는 다른 어떤 클래스를 확장하기위한 공간을 저장할 수 있습니다.

  • Java는 다중 상속을 지원하지 않습니다. 즉, 하나의 클래스 만 Java로 확장 할 수 있으므로 Thread 클래스를 확장하면 기회가 없어지고 Java의 다른 클래스를 상속하거나 상속 할 수 없습니다.

  • 객체 지향 프로그래밍에서 클래스를 확장한다는 것은 일반적으로 새로운 기능을 추가하고 동작을 수정하거나 개선하는 것을 의미합니다. Thread에 수정을 가하지 않으면 대신 Runnable 인터페이스를 사용하십시오.

  • Runnable 인터페이스는 일반 Thread 또는 Executors 또는 다른 방법으로 실행할 수있는 Task를 나타냅니다. Thread보다 Runnable로 Task를 논리적으로 분리하는 것은 좋은 설계 결정입니다.

  • 태스크를 Runnable로 분리한다는 것은 태스크를 재사용 할 수 있다는 것을 의미하며 다른 방법으로 태스크를 실행할 수있는 자유를 의미합니다. 스레드가 완료되면 다시 시작할 수 없기 때문입니다. 다시 Runnable 대 Thread for task, Runnable이 승자입니다.

  • Java 디자이너는 이것을 인식하고 그 때문에 Executors는 Runnable as Task를 수락하고 작업을 실행하는 작업자 스레드를 가지고 있습니다.

  • 모든 Thread 메소드를 상속하는 것은 Runnable로 쉽게 할 수있는 Task를 표현하기위한 추가적인 오버 헤드이다.

javarevisited.blogspot.com 의례

Thread와 Runnable의 차이점은 Thread와 Runnable의 차이점입니다. 저는 개인적으로이 시나리오를 위해 Runnable over Thread를 사용하고 요구 사항에 따라 Runnable 또는 Callable 인터페이스를 사용할 것을 권장합니다.

그러나 중요한 차이점이 있습니다.

extends Thread 클래스를 extends Thread 하면 각 스레드는 고유 한 객체를 생성하고 스레드와 연관시킵니다. 당신이 implements Runnableimplements Runnable 때, 그것은 같은 스레드를 여러 스레드에 공유합니다.


이것이 매우 인기있는 주제이고 좋은 답변이 온통 퍼져 다룰 때, 나는 다른 사람들의 좋은 대답을 좀 더 간결한 형식으로 컴파일하는 것이 정당하다고 느꼈으므로 이민자는 쉬운 개요를 선행합니다.

  1. 일반적으로 기능을 추가하거나 수정하기 위해 클래스를 확장합니다. 따라서, Thread Behavior덮어 쓰지 않으려면 Runnable을 사용하십시오.

  2. 동일한 방법으로 스레드 메소드를 상속 할 필요가 없다면 Runnable을 사용하여 오버 헤드 없이 수행 할 수 있습니다.

  3. 단일 상속 : 스레드를 확장하면 다른 클래스에서 확장 할 수 없으므로 필요한 경우 Runnable을 사용해야합니다.

  4. 도메인 논리를 기술적 수단과 분리하는 것이 좋은 설계입니다. 그런 의미 에서 러너 로부터 작업을 격리시키는 Runnable 작업을 갖는 것이 좋습니다.

  5. 같은 Runnable 객체를 여러 번 실행할 수 있지만, Thread 객체는 한 번만 시작할 수 있습니다. (이유는, Executors가 Runnables를 받아들이는 것, Thread는 받아들이지 않는 이유입니다).

  6. Runnable로 작업을 개발 하면 현재와 미래의 모든 방법을 융통성있게 사용할 수 있습니다 . Executors를 통해 동시에 Thread를 통해 실행할 수 있습니다. 그리고 당신은 여전히 ​​다른 일반적인 유형 / 객체처럼 동일한 스레드 내에서 비 ​​동시 적으로 사용하거나 호출 할 수 있습니다.

  7. 따라서 유닛 테스트 에서 태스크 로직과 동시성 측면분리 하는 것이 더 쉽습니다.

  8. 이 질문에 관심이 있으시면 Callable과 Runnable차이점에 관심이있을 것입니다.


다음 이유로 인해 실행 가능합니다.

  • Runnable 구현이 다른 클래스를 확장 할 수있는 유연성을 제공합니다.
  • 코드를 실행과 분리합니다.
  • 스레드 풀, 이벤트 스레드 또는 향후 다른 방법으로 실행 가능한 runnable을 허용합니다.

지금 당장 당신이 필요하지 않더라도, 당신은 미래에있을 수 있습니다. Thread를 오버라이드하는 것은 아무런 이점이 없으므로 Runnable이 더 나은 해결책입니다.


우리 반이 우리가 원하는 행동을 취하기위한 기본 이유를 다시 방문 할 수 있습니까 Thread? 아무 이유도 없으며, 우리는 단지 비동기 모드에서 작업을 수행하기를 원했습니다. 이것은 조기에 끝나면 기다릴 수도 있고하지 않을 수도있는 작업의 실행이 메인 스레드와 메인 스레드에서 분기되어야한다는 것을 의미합니다 분기 된 경로 (작업).

이것이 전체 목적이라면, 어디에서 전문화 된 스레드가 필요한지를 알 수 있습니다. 이것은 시스템의 쓰레드 풀에서 RAW 쓰레드를 선택하고 우리의 태스크 (우리 클래스의 인스턴스가 될 수 있습니다)를 할당함으로써 수행 될 수 있습니다.

OOP 개념을 따르고 필요한 유형의 클래스를 작성하겠습니다. 여러 가지 방법으로 일을 할 수 있으며 올바른 방법으로 문제를 해결할 수 있습니다.

우리는 작업이 필요하므로 스레드에서 실행할 수있는 작업 정의를 작성하십시오. 그래서 Runnable을 사용하십시오.

항상 기억 implements은 행동을 부여하는 데 특별히 사용되며 extends기능 / 속성을 부여하는 데 사용됩니다.

쓰레드의 프로퍼티를 원하지 않고 클래스가 실행될 수있는 태스크로 동작하기를 원합니다.


Java 8의 릴리스에는 세 번째 옵션이 있습니다.

Runnable함수 인터페이스로 , 람다 표현식이나 메소드 참조로 인스턴스를 생성 할 수 있습니다.

귀하의 예는 다음으로 대체 될 수 있습니다 :

new Thread(() -> { /* Code here */ }).start()

또는 ExecutorService 및 메서드 참조를 사용하려는 경우 :

executor.execute(runner::run)

이것들은 예제보다 훨씬 짧을뿐만 아니라 스레드의 동작을 전문적으로 다루지 않기 때문에 단일 책임 및 컴포지션 사용과 같은 Runnable over Thread 사용에 대한 다른 대답에서 언급 된 많은 장점이 있습니다. 이 방법을 사용하면 예제에서와 같이 Runnable 있으면 필요한 클래스를 추가로 만들지 않아도됩니다.


이야기의 교훈:

일부 동작을 재정의하려는 경우에만 상속받습니다.

또는 다음과 같이 읽어야합니다.

상속을 줄이고 더 많은 인터페이스를 제공합니다.


예. ThreadA 호출을 호출하면 시작 메소드를 호출 할 필요가 없으며 ThreadA 클래스 만 호출 한 후 호출 메소드를 호출 할 수 있습니다. 그러나 ThreadB 호출을 사용한다면 호출 실행 메소드의 시작 스레드가 필요합니다. 더 이상 도움이 필요하면 저에게 답장하십시오.


인터페이스를 인스턴스화하면 (자), 코드와 thread의 구현이 명확하게 분리되므로,이 경우는 Runnable를 구현하는 편이 좋을 것입니다.


  1. Java는 다중 상속을 지원하지 않습니다. 즉, 하나의 클래스 만 Java로 확장 할 수 있으므로 Thread 클래스를 확장하면 기회가 없어지고 Java의 다른 클래스를 상속하거나 상속 할 수 없습니다.
  2. 객체 지향 프로그래밍에서 클래스를 확장하는 것은 일반적으로 새로운 기능을 추가하고 동작을 수정하거나 개선하는 것을 의미합니다. 우리가 Thread 수정을 가하지 않는다면 대신에 Runnable 인터페이스를 사용하십시오.
  3. Runnable 인터페이스는 일반 Thread 또는 Executors 또는 다른 방법으로 실행할 수있는 Task 를 나타냅니다. 그래서 Thread 보다 Runnable 으로 Task 를 논리적으로 분리하는 것은 좋은 설계 결정입니다.
  4. 태스크를 Runnable 로 분리한다는 것은 태스크를 재사용 할 수 있다는 것을 의미하며 다른 방법으로 태스크를 실행할 수있는 자유를 의미합니다. 일단 완료되면 (자), Thread 재기동 할 수 없기 때문에, Runnable vs Thread for task, Runnable 가 승자가됩니다.
  5. Java 디자이너는 이것을 인식하고 그 때문에 ExecutorsRunnable as Task 수락하고 Task 을 실행하는 작업자 스레드를 가지고 있습니다.
  6. 모든 Thread 메소드를 상속하는 것은 Runnable 쉽게 할 수있는 Task 를 표현하기위한 추가적인 오버 헤드이다.




java-threads