문제

나는 Java에서 스레드를 사용하면서 스레드를 작성하는 다음 두 가지 방법을 발견했습니다.

와 함께 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 이를 선호하는 방법입니다. 당신은 실제로 스레드의 행동을 전문화하지 않습니다. 당신은 그냥 실행할 무언가를주고 있습니다. 그것의 의미는 구성 입니다 철학적으로 "더 순수한"방법.

~ 안에 현실적인 용어는 구현할 수 있음을 의미합니다 Runnable 다른 수업에서도 확장됩니다.

다른 팁

tl; dr : chable이 더 낫습니다. 그러나 경고는 중요합니다

일반적으로 나는 같은 것을 사용하는 것이 좋습니다 Runnable 보다는 Thread 그것은 당신이 선택한 동시성과 느슨하게 결합 할 수 있기 때문에, 당신은 당신의 동시성을 느슨하게 결합시킬 수 있기 때문입니다. 예를 들어, a를 사용하는 경우 Runnable 그리고 나중에 이것은 실제로 자신의 것이 필요하지 않습니다. Thread, 당신은 그냥 threada.run ()을 호출 할 수 있습니다.

경고: 여기 주변에서, 나는 원시 실의 사용을 강력히 낙담시킵니다. 나는 사용을 훨씬 선호합니다 콜블 즈 그리고 FutureTasks (Javadoc에서 : "취소 가능한 비동기 계산"). 타임 아웃의 통합, 적절한 취소 및 현대 동시성 지원의 스레드 풀링은 원시 스레드 더미보다 훨씬 더 유용합니다.

후속 조치 : ~이있다 FutureTask 건설자 이를 통해 Runnables를 사용할 수 있으며 (가장 편한 경우) 현대 동시성 도구의 이점을 얻을 수 있습니다. Javadoc을 인용합니다:

특정 결과가 필요하지 않은 경우 양식의 구성을 고려하십시오.

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

그래서 우리가 그들의 대체한다면 runnable 당신과 함께 threadA, 우리는 다음을 얻습니다.

new FutureTask<Object>(threadA, null)

Runnables에 더 가까이있을 수있는 또 다른 옵션은 다음과 같습니다. ThreadPooleExecutor. 당신은 사용할 수 있습니다 실행하다 "미래에 언젠가 주어진 작업"을 실행하기 위해 실행 가능한 방법을 전달하는 방법.

스레드 풀을 사용하려면 위의 코드 조각이 다음과 같은 것과 같습니다. Executors.newCachedThreadpool () 공장 방법) :

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

이야기의 교훈:

동작을 무시하려는 경우에만 상속하십시오.

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

덜 상속하고 인터페이스를 더 많이 상속합니다.

너무 많은 좋은 답변, 나는 이것에 더 많은 것을 더하고 싶습니다. 이것은 이해하는 데 도움이 될 것입니다 Extending v/s Implementing Thread.
확장은 두 개의 클래스 파일을 매우 밀접하게 바인딩하며 코드를 다루기가 어려울 수 있습니다.

두 가지 접근 방식 모두 동일한 작업을 수행하지만 약간의 차이점이있었습니다.
가장 일반적인 차이점은입니다

  1. 스레드 클래스를 확장 할 때 필요한 다른 클래스를 연장 할 수 없습니다. (아시다시피, Java는 둘 이상의 클래스를 상속하는 것을 허용하지 않습니다).
  2. Runnable을 구현하면 수업이 미래 또는 현재 다른 클래스를 확장 할 수있는 공간을 절약 할 수 있습니다.

그러나 하나 확연히 다른 실행 가능한 구현과 스레드를 구현하는 것 사이는 그 것입니다
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 the 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

실행 가능한 인터페이스 접근 방식에서 클래스의 하나의 인스턴스 만 생성되고 있으며 다른 스레드에 의해 공유되었습니다. 따라서 카운터 값은 각 스레드 액세스마다 증가합니다.

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

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

실행 가능한 클래스는 스레드가 아니라 수업 일뿐입니다. 런닝 가능한 스레드가 되려면 스레드 인스턴스를 만들고 대상으로 전달해야합니다.

대부분의 경우, 실행 가능한 인터페이스는 run() 방법 및 기타 스레드 방법이 없습니다. 프로그래머가 클래스의 기본 행동을 수정하거나 향상 시키려고하지 않는 한 클래스는 서브 클래스를 사용해서는 안되기 때문에 이것은 중요합니다.

슈퍼 클래스를 확장 해야하는 경우 스레드 클래스를 사용하는 것보다 런닝 가능한 인터페이스를 구현하는 것이 더 적절합니다. 실행 가능한 인터페이스를 구현하여 스레드를 만들 수있는 다른 클래스를 확장 할 수 있기 때문입니다.

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

내가 놀랐던 한 가지는 아직 언급되지 않았다. Runnable 수업을보다 유연하게 만듭니다.

스레드를 확장하면 당신이하는 행동은 항상 실에있을 것입니다. 그러나 구현하는 경우 Runnable 그럴 필요는 없습니다. 스레드에서 실행하거나 어떤 종류의 유원기 서비스로 전달하거나 단일 스레드 애플리케이션 내에서 작업으로 전달할 수 있습니다 (나중에는 동일한 스레드 내에서 실행할 수 있음). 만 사용하면 옵션이 훨씬 더 열려 있습니다. Runnable 당신이 자신을 묶는 것보다 Thread.

다른 수업을 구현하거나 연장하려면 Runnable 다른 클래스가 확장되거나 구현되기를 원하지 않는 경우 인터페이스가 가장 바람직합니다. Thread 클래스가 바람직합니다.

가장 일반적인 차이점은입니다

enter image description here

때를 extends Thread 클래스, 그 후에는 필요한 다른 클래스를 연장 할 수 없습니다. (아시다시피, Java는 둘 이상의 클래스를 상속하는 것을 허용하지 않습니다).

때를 implements Runnable, 당신은 당신의 수업이 미래에 다른 수업을 연장 할 수있는 공간을 절약 할 수 있습니다.

  • Java는 여러 상속을 지원하지 않으므로 Java에서 하나의 클래스 만 확장 할 수 있으므로 스레드 클래스를 확장하면 기회를 잃었고 Java에서 다른 클래스를 확장하거나 상속받을 수 없습니다.

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

  • 실행 가능한 인터페이스는 일반 스레드 또는 집행자 또는 기타 수단에 의해 실행될 수있는 작업을 나타냅니다. 따라서 스레드보다 실행 가능한 작업을 논리적으로 분리하는 것은 좋은 디자인 결정입니다.

  • 작업을 실행 가능한 것으로 분리하면 작업을 재사용 할 수 있으며 다른 수단에서 작업을 실행할 수있는 자유가 있습니다. 스레드가 완료되면 다시 시작할 수 없으므로. 다시 실행 가능한 vs 스레드 작업을 위해 Runnable이 승자입니다.

  • Java Designer는 이것을 인식하고 이것이 유언 집행 인이 작업으로 런 가능하게 받아들이고 해당 작업을 실행하는 작업자 스레드를 가지고있는 이유입니다.

  • 모든 스레드 방법을 상속하는 것은 런 가능성으로 쉽게 수행 할 수있는 작업을 나타내는 추가 오버 헤드입니다.

제공합니다 javarevisited.blogspot.com

이것들은 Java에서 스레드와 실행 가능한 스레드의 주목할만한 차이점 중 일부였습니다. 스레드 대 실행 가능한 다른 차이점을 알고 있다면 주석을 통해 공유하십시오. 이 시나리오에서는 개인적으로 실행 가능한 스레드를 사용하며 요구 사항에 따라 실행 가능 또는 호출 가능한 인터페이스를 사용하는 것이 좋습니다.

그러나 중요한 차이는입니다.

때를 extends Thread 클래스, 각 스레드는 고유 한 객체를 생성하고 그것과 연결합니다. 때를 implements Runnable, 동일한 객체를 여러 스레드와 공유합니다.

실제로 비교하는 것이 현명하지 않습니다 Runnable 그리고 Thread 서로 서로 함께.

이 두 사람은 멀티 스레딩에서 의존성과 관계를 가지고 있습니다. Wheel and Engine 자동차의 관계.

나는 두 단계로 멀티 스레딩의 한 가지 방법 만 있다고 말할 것입니다. 내 요점을 만들어 드리겠습니다.

실행 가능 :
구현할 때 interface Runnable 그것은 당신이 무언가를 만들고 있다는 것을 의미합니다 run able 다른 스레드에서. 이제 스레드 내부에서 실행할 수있는 것을 만들어 낸다 (스레드 내부에서 실행 가능)는 스레드를 만드는 것을 의미하지는 않습니다.
그래서 수업 MyRunnable a void run 방법. 그리고 객체는 방법 만있는 일반적인 객체가 될 것입니다. run 호출되면 정상적으로 실행됩니다. (우리가 실에서 객체를 전달하지 않는 한).

실:
class Thread, 나는 실제로 새로운 스레드를 시작할 수있는 능력을 가진 매우 특별한 클래스를 말할 것입니다. start() 방법.

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

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

  • 스레드 안에서 실행할 수있는 것 (런 가능).
  • 새 스레드 (스레드)를 시작할 수있는 것.

따라서 기술적으로나 이론적으로는 스레드를 시작하는 데 필요합니다. 운영 그리고 하나의 의지 실행하십시오 (처럼 Wheel and Engine 자동차).

그렇기 때문에 스레드를 시작할 수 없습니다. MyRunnable 인스턴스로 전달해야합니다 Thread.

하지만 사용하는 스레드 만 만들고 실행할 수 있습니다. class Thread 수업 때문에 Thread 구현 Runnable 그래서 우리 모두는 알고 있습니다 Thread 또한 a Runnable 내부에.

드디어 Thread 그리고 Runnable 경쟁사 나 교체가 아닌 멀티 스레딩을 위해 서로 보완됩니다.

Runnable을 구현해야하지만 Java 5 이상에서 실행중인 경우 시작해서는 안됩니다. new Thread 그러나 사용하십시오 ExecutorService 대신에. 자세한 내용은 다음을 참조하십시오. Java에서 간단한 스레딩을 구현하는 방법.

나는 전문가가 아니지만 스레드 대신 런 가능성을 구현 해야하는 한 가지 이유를 생각할 수 있습니다. Java는 단일 상속 만 지원하므로 하나의 클래스 만 확장 할 수 있습니다.

편집 : 원래 "인터페이스를 구현하려면 더 적은 리소스가 필요합니다"라고 말했습니다. 또한, 그러나 어느 쪽이든 새 스레드 인스턴스를 만들어야하므로 잘못되었습니다.

세 번째 방법이 있다고 말할 것입니다.

public class Something {

    public void justAnotherMethod() { ... }

}

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

어쩌면 이것은 최근에 JavaScript와 ActionScript 3을 많이 사용하여 약간 영향을 미쳤을 것입니다. 그러나 이런 식으로 당신의 클래스는 매우 모호한 인터페이스를 구현할 필요가 없습니다. Runnable.

Java 8이 출시되면 이제 세 번째 옵션이 있습니다.

Runnable a 기능 인터페이스, 이는 Lambda 표현식 또는 메소드 참조로 IT 인스턴스를 만들 수 있음을 의미합니다.

예제를 대체 할 수 있습니다.

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

또는 사용하려면 ExecutorService 및 메소드 참조 :

executor.execute(runner::run)

이것들은 당신의 예보다 훨씬 짧을뿐만 아니라 사용에 대한 다른 답변에 언급 된 많은 장점들도 있습니다. Runnable ~ 위에 Thread, 스레드의 행동을 전문으로하지 않기 때문에 단일 책임 및 구성 사용과 같은 구성. 이 방법은 또한 필요한 모든 것이 필요한 경우 추가 수업을 피하는 것을 피합니다. Runnable 당신이 당신의 예에서와 마찬가지로.

인터페이스를 인스턴스화하면 코드와 스레드 구현이 더욱 명확하게 구분되므로 이 경우에는 Runnable을 구현하는 것이 좋습니다.

여기있는 모든 사람들은 런닝 가능을 구현하는 것이 갈 길이라고 생각하는 것 같습니다. 나는 그들에게 실제로 동의하지 않지만 내 의견으로는 스레드를 확장 할 경우도 있습니다. 사실 당신은 당신의 코드에서 그것을 입증했습니다.

runnable을 구현 한 경우 runnable을 구현하는 클래스는 스레드 이름을 제어 할 수 없으며 다음과 같이 스레드 이름을 설정할 수있는 호출 코드입니다.

new Thread(myRunnable,"WhateverNameiFeelLike");

그러나 스레드를 확장하면 클래스 자체 내에서 이것을 관리하게됩니다 (예에서와 같이 스레드 '스레드 B'라고합니다). 이 경우 :

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

b) 해당 클래스의 모든 사례에 해당 이름이 사용되도록 강요하고 있습니다 (실이라는 사실을 무시하고 위의 일을 마치 실행 가능하는 것처럼 위의 작업을 수행하지 않는 한, 우리는 여기서 컨벤션에 대해 이야기하고 있습니다. 내가 느끼는 가능성을 무시하십시오).

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

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

물론 당신은 또한 이름을 제작 호출의 스택 트레이스로 설정 한 다음 표준 Java 스레드 클래스 대신 실행 가능한 구현과 함께 사용하는 스레드 클래스의 확장을 만들어 위의 일반적인 방식으로 위의 방식으로 수행 할 수 있다고 말했습니다. (아래 참조) 그러나 스택 추적 외에도 디버깅의 스레드 이름에 유용한 컨텍스트 별 정보가있을 수 있습니다 (예를 들어 처리 할 수있는 많은 대기열 또는 소켓 중 하나에 대한 참조. 해당 케이스에 대해 구체적으로 스레드를 확장하여 컴파일러가 귀하 (또는 라이브러리를 사용하는 다른 사람)가 특정 정보 (예 : 이름에 사용하기 위해 문제의 대기열/소켓)를 전달하도록 강제로 전달할 수 있도록합니다.

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

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]

실행 가능 :

  • 실행 가능한 구현이 다른 클래스를 확장 할 수있는 유연성을 더 많이 남깁니다.
  • 코드를 실행에서 분리합니다
  • 스레드 풀, 이벤트 스레드 또는 미래의 다른 방법으로 실행 가능하게 실행할 수 있습니다.

지금이 중 어느 것도 필요하지 않더라도 미래에있을 수 있습니다. 스레드를 재정의하는 데 이점이 없기 때문에 런 가능이 더 나은 솔루션입니다.

이것은 매우 인기 있는 주제이고 좋은 답변이 곳곳에 퍼져 있고 깊이 있게 다루어지기 때문에 다른 사람들의 좋은 답변을 보다 간결한 형태로 정리하는 것이 타당하다고 느꼈습니다. 그러면 새로 온 사람들이 미리 쉽게 개요를 볼 수 있습니다.

  1. 일반적으로 기능을 추가하거나 수정하기 위해 클래스를 확장합니다.그래서, 당신이 원하지 않는다면 에게 덮어쓰기 어느 스레드 동작, Runnable을 사용하십시오.

  2. 같은 맥락에서, 필요하지 않다면 에게 상속하다 스레드 방법, 그것 없이도 할 수 있습니다 간접비 Runnable을 사용하여.

  3. 단일 상속:Thread를 확장하면 다른 클래스에서는 확장할 수 없으므로 그렇게 해야 한다면 Runnable을 사용해야 합니다.

  4. 기술적인 수단과 도메인 로직을 분리하는 것은 좋은 설계입니다. 그런 의미에서 Runnable 작업을 갖는 것이 더 좋습니다. 격리 당신의 작업 당신의 달리는 사람.

  5. 당신은 할 수 있습니다 실행하다 동일한 실행 가능 객체를 여러 번, 그러나 Thread 개체는 한 번만 시작할 수 있습니다.(Executor가 Runnable을 허용하지만 Thread는 허용하지 않는 이유일 수 있습니다.)

  6. 작업을 Runnable로 개발하면 현재와 ​​미래에 사용하는 방법에 대한 모든 유연성.Executors뿐만 아니라 Thread를 통해서도 동시에 실행할 수 있습니다.그리고 다른 일반 유형/객체와 마찬가지로 동일한 스레드 내에서 비동시적으로 사용/호출할 수도 있습니다.

  7. 이는 또한 분리된 작업 논리 및 동시성 측면 당신의 단위 테스트.

  8. 이 질문에 관심이 있다면 다음에도 관심이 있으실 것입니다. 호출 가능과 실행 가능의 차이점.

스레드 확장과 런 가능 구현의 차이점은 다음과 같습니다.

enter image description here

이것은 오라클에서 논의됩니다 스레드를 정의하고 시작합니다 지도 시간:

이 관용구 중 어떤 관용구를 사용해야합니까? 런닝 가능한 객체를 사용하는 첫 번째 관용구는 더 일반적입니다. 런닝 가능한 객체는 스레드 이외의 클래스를 서브 클래스 할 수 있기 때문입니다. 두 번째 관용구는 간단한 응용 프로그램에서 사용하기 쉽지만 작업 클래스는 스레드의 후손이어야한다는 사실에 의해 제한됩니다. 이 레슨은 첫 번째 접근 방식에 중점을 두어 작업을 실행하는 스레드 객체에서 실행 가능한 작업을 분리합니다. 이 접근법은 더 유연 할뿐만 아니라 나중에 다루는 고급 스레드 관리 API에 적용 할 수 있습니다.

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

내가 틀리지 않으면 다소 비슷합니다.

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

확장 "확장"a"관계 및 인터페이스 제공"a"기능.

선호하다 실행 가능합니다 :

  1. 스레드 클래스를 확장하고 스레드 API 기본 구현을 수정할 필요가없는 경우
  2. 화재를 처형하고 명령을 잊어 버린 경우
  3. 이미 다른 수업을 연장하는 경우

선호하다 "스레드를 확장합니다" :

  1. 이 중 하나를 무시 해야하는 경우 Oracle 문서 페이지에 나열된 방법

일반적으로 스레드 동작을 무시할 필요가 없습니다. 그래서 실행 가능합니다 대부분의 시간 동안 선호됩니다.

다른 메모로 고급 사용 ExecutorService 또는 ThreadPoolExecutorService API는 더 많은 유연성과 제어를 제공합니다.

이 SE 질문을 살펴보십시오.

ExecutorService vs 캐주얼 스레드 Spawner

가장 간단한 설명은 구현하는 것입니다 Runnable 동일한 객체를 여러 스레드와 각각에 할당 할 수 있습니다. Thread 동일한 객체 상태와 동작을 공유합니다.

예를 들어, 두 개의 스레드가 있다고 가정합니다. 스레드 1 정수를 배열에 넣습니다 스레드 2 배열이 채워질 때 배열에서 정수를 가져옵니다. 그것을 위해 그것을 주목하십시오 스레드 2 작동하려면 배열 상태를 알아야합니다. 스레드 1 그것을 채웠는지 아닌지.

구현 Runnable 객체를 공유 할 수있는 유연성을 가질 수 있습니다. extends Thread 각 스레드마다 새 객체를 만들 수 있으므로 Thread1에서 수행하는 업데이트는 Thread2로 손실됩니다.

실행 가능한 구현에서 스레드 클래스를 분리하면 스레드와 run () 메소드 사이의 잠재적 동기화 문제도 피할 수 있습니다. 별도의 실행 가능은 일반적으로 실행 가능한 코드를 참조하고 실행하는 방식에서 더 큰 유연성을 제공합니다.

그게 다야 에스 ~의 단단한:단일 책임.

을 구현 실행 중인 컨텍스트 (실행 컨텍스트에서와 같이:스택 프레임, 스레드 ID 등) 비동기 실행 코드 조각.저것 코드 조각 이상적으로는 동일한 구현이어야 합니다. 동기식 또는 비동기식.

하나의 구현으로 함께 묶으면 결과 객체에 두 개가 제공됩니다. 관련이 없는 변화의 원인:

  1. 애플리케이션의 스레드 처리(예:실행 컨텍스트 쿼리 및 수정)
  2. 코드 조각(실행 가능한 부분)으로 구현된 알고리즘

사용하는 언어가 부분 클래스나 다중 상속을 지원하는 경우 각 원인을 자체 슈퍼 클래스로 분리할 수 있지만 기능 세트가 겹치지 않기 때문에 결국 두 개체를 구성하는 것과 동일하게 됩니다.그것은 이론을 위한 것입니다.

실제로는 일반적으로 말해서 프로그램이 필요 이상으로 복잡할 필요는 없습니다.특정 작업을 수행하는 하나의 스레드가 있고 해당 작업을 변경하지 않은 경우 작업을 별도의 클래스로 만드는 것은 아마도 의미가 없으며 코드는 더 단순하게 유지됩니다.

문맥 상에 자바, 시설이 좋기 때문에 이미 거기에, 아마도 독립 실행형으로 직접 시작하는 것이 더 쉬울 것입니다. Runnable 클래스에 해당 인스턴스를 전달합니다. Thread (또는 Executor) 사례.한 번 사용된 해당 패턴에 따르면 간단한 실행 가능 스레드 사례보다 사용(또는 읽기)이 더 어렵지 않습니다.

기본 클래스를 확장하기보다는 인터페이스를 구현하려는 한 가지 이유는 이미 다른 클래스를 확장하고 있기 때문입니다. 하나의 클래스 만 확장 할 수 있지만 여러 인터페이스를 구현할 수 있습니다.

스레드를 확장하면 기본적으로 'this'이외의 다른 스레드가 논리를 실행하는 것을 방지합니다. 당신이 원한다면 약간 논리를 실행하는 스레드, 런 가능 만 구현하는 것이 좋습니다.

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

우리가 수업을 원한 기본 이유를 다시 방문 할 수 있습니까? Thread? 이유가 전혀 없습니다. 우리는 단지 비동기 모드에서 과제를 실행하고 싶었습니다. 이는 작업의 실행이 기본 스레드에서 분기되어야한다는 것을 의미합니다. 분기 경로 (작업)의 경우.

이것이 전체 목적이라면, 전문 스레드가 필요하다는 것을 어디에서 볼 수 있습니까? 이것은 시스템의 스레드 풀에서 원시 스레드를 집어 들고 우리의 작업 (클래스의 인스턴스 일 수 있음)을 할당하여 달성 할 수 있습니다.

따라서 oops 개념에 순종하고 필요한 유형의 클래스를 작성하겠습니다. 올바른 방법으로 일을하는 방법에는 여러 가지가 있습니다.

작업이 필요하므로 스레드에서 실행할 수있는 작업 정의를 작성하십시오. 그러니 달리기를 사용하십시오.

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

우리는 스레드의 속성을 원하지 않으며 대신 수업이 실행할 수있는 작업으로 행동하기를 원합니다.

예, Threada Call을 호출하는 경우 START 메소드를 호출 할 필요가 없으며 RUN 메소드는 Call The Threada 클래스 만 호출합니다. 그러나 ThreadB 호출을 사용하면 통화 실행 메소드의 시작 스레드가 필요합니다. 더 많은 도움이 있으면 답장하십시오.

언급 된 모든 이유로 런 가능성을 사용하는 것이 가장 유용하지만 때로는 스레드를 확장하여 나만의 스레드 중지 방법을 만들고 생성 한 스레드에서 직접 호출 할 수 있습니다.

Java는 다중 유전을 지원하지 않으므로 스레드 클래스를 확장하면 다른 클래스가 확장되지 않습니다.

예 : 애플릿을 만들면 애플릿 클래스를 확장해야하므로 여기에서 스레드를 생성하는 유일한 방법은 런닝 가능한 인터페이스를 구현하는 것입니다.

Runnable 인터페이스입니다 Thread 이 인터페이스를 구현하는 클래스입니다. 설계 관점에서 작업이 정의되는 방식과 실행 방법 사이에는 깨끗한 분리가 있어야합니다. 전자는 a의 책임이다 Runnalbe 구현, 후자는 Thread 수업. 대부분의 경우 구현 Runnable 따라야 할 올바른 방법입니다.

스레드와 실행 가능한 차이. 스레드 클래스를 사용하여 스레드를 생성하는 경우 스레드 수를 생성 한 객체 수와 동일한 스레드 수입니다. 실행 가능한 인터페이스를 구현하여 스레드를 작성하는 경우 여러 스레드를 생성하기 위해 단일 객체를 사용할 수 있습니다. 따라서 단일 객체는 여러 스레드에서 공유됩니다. 따라서 메모리가 줄어 듭니다.

따라서 데이터가 Senstive가 아닌 경우 요구 사항에 따라. 따라서 Runnable 인터페이스를 사용할 수있는 여러 스레드간에 공유 할 수 있습니다.

여기에 내 두 센트를 추가 -항상 사용할 때마다 implements Runnable . 아래는 사용하지 않아야하는 이유에 대한 두 가지 경고입니다.extends Thread에스

  1. 이상적으로는 스레드 클래스를 확장해서는 안됩니다. 그만큼 Thread 수업을 만들어야합니다 final. 적어도 그 방법은 같은 방법입니다 thread.getId(). 보다 이것 확장과 관련된 버그에 대한 토론 Thread에스.

  2. 퍼즐을 풀기를 좋아하는 사람들은 스레드를 확장하는 또 다른 부작용을 볼 수 있습니다. 아래 코드는 아무도 알리지 않으면 도달 할 수없는 코드를 인쇄합니다.

참조하십시오 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 ");
        }
    } 
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top