Java에서 "실행 가능" 대 "스레드 확장"
몇 시부터 실과 함께 보냈다.Java
스레드를 쓰는 두 가지 방법을 찾았어
도구 포함:
public class MyRunnable implements Runnable {
public void run() {
//Code
}
}
//Started with a "new Thread(new MyRunnable()).start()" call
또는 확장 시:
public class MyThread extends Thread {
public MyThread() {
super("MyThread");
}
public void run() {
//Code
}
}
//Started with a "new MyThread().start()" call
이 두 블록의 코드에서 유의미한 차이가 있는가?
예 : 구현Runnable
선호하는 방법이야, IMO. 넌 실의 행동을 전문으로 다루는 게 아니야.넌 도망칠 뭔가를 주는 거야그것은 구성이 철학적으로 "순수"하는 방법이라는 것을 의미한다.
실용적인 측면에서, 그것은 당신이 실행 할 수 있다는 것을 의미한다.Runnable
그리고 다른 수업에서도...그리고 당신은 또한 실행 할 수 있다.Runnable
자바 8의 람다 식을 통해.
tl;dr: Runnable이 더 낫다고 구현한다. 그러나 주의사항은 중요하다.
일반적으로, 나는 다음과 같은 것을 사용하는 것을 추천한다.Runnable
Thread
왜냐하면 그것은 당신이 당신의 일을 당신의 동시성 선택과 느슨하게 결합시킬 수 있게 해주기 때문이다.예를 들어, a를 사용하는 경우Runnable
그리고 나중에 이 일이 사실 그것만의 것을 요구하지 않는다는 것을 결정한다.Thread
스레드 A.run()이라고 불러도 된다.
주의바트: 이 근처에서는, 나는 날것의 사용을 강하게 단념한다.나는 Callables와 FutureTasks의 사용을 훨씬 더 선호한다(자바독으로부터: "취소 가능한 비동기 계산").타임아웃의 통합, 적절한 취소, 현대의 동시성 지원의 스레드 풀링 등은 모두 생 쓰레드 더미보다 내게 훨씬 더 유용하다.
후속 조치:런너블(당신이 가장 편한 것이라면)을 사용할 수 있게 해주고, 여전히 현대의 동시성 도구의 장점을 얻을 수 있게 해주는 생성자가 있다.자바도를 인용하려면:
특정 결과가 필요하지 않을 경우 양식 구조를 사용하는 것을 고려해 보십시오.
Future<?> f = new FutureTask<Object>(runnable, null)
그래서 만약 우리가 그들의runnable
당신의 것과 함께threadA
, 다음과 같은 정보를 얻는다.
new FutureTask<Object>(threadA, null)
Runnables에 더 가까이 머무를 수 있는 또 다른 옵션은 ThreadPoolExecutor이다.실행 방법을 사용하여 "앞으로 지정된 태스크"를 실행하기 위해 실행 가능으로 전달할 수 있다.
스레드 풀을 사용하려는 경우 위의 코드 조각은 다음과 같은 것이 된다(실행자.newCachedThreadPool() 공장 방법 사용).
ExecutorService es = Executors.newCachedThreadPool();
es.execute(new ThreadA());
이야기의 교훈:
일부 동작을 재정의하려는 경우에만 상속하십시오.
또는 다음과 같이 읽어야 한다.
더 적은 비용으로 더 많은 인터페이스를 상속하십시오.
좋은 답변이 너무 많네, 여기에 더 보태고 싶어.이것은 이해하는데 도움이 될 것이다.Extending v/s Implementing Thread
.
Extension은 두 개의 클래스 파일을 매우 밀접하게 바인딩하여 코드를 처리하기 상당히 어려울 수 있다.
두 방법 모두 같은 역할을 하지만 약간의 차이가 있었다.
가장 일반적인 차이점은
- 스레드 클래스를 확장한 후 필요한 다른 클래스를 확장할 수 없음.(자바에서는 아시다시피 둘 이상의 클래스 상속을 허용하지 않는다.)
- 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 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
실행 가능한 인터페이스 접근 방식에서 클래스의 인스턴스는 하나만 생성되고 다른 스레드에 의해 공유된다.따라서 각 스레드 액세스마다 카운터의 값이 증가한다.
반면, 스레드 클래스 접근 방식은 모든 스레드 액세스에 대해 별도의 인스턴스를 만들어야 한다.따라서 모든 클래스 인스턴스에 서로 다른 메모리가 할당되고 각 메모리는 별도의 카운터를 가지며, 값은 동일하게 유지되며, 이는 개체 참조 중 어느 것도 동일하지 않기 때문에 증분이 발생하지 않음을 의미한다.
Runnable을 언제 사용해야 하는가?
스레드 그룹에서 동일한 리소스에 액세스하려면 실행 가능한 인터페이스를 사용하십시오.여러 개체를 생성하면 메모리를 더 많이 소모하고 성능 오버헤드가 커지기 때문에 스레드 클래스는 사용하지 마십시오.
Runnable을 구현하는 클래스는 스레드가 아니고 클래스일 뿐이다.실행 가능이 스레드가 되려면 스레드의 인스턴스를 만들고 자신을 대상으로 전달해야 한다.
대부분의 경우 Runnable 인터페이스는 Runnable 인터페이스만 재정의할 계획인 경우 사용해야 한다.run()
방법 및 다른 스레드 방법 없음.이것은 프로그래머가 수업의 기본 행동을 수정하거나 향상시키려 하지 않는 한 수업을 하위 분류해서는 안 되기 때문에 중요하다.
슈퍼클래스를 확장할 필요가 있을 때, Runnable 인터페이스를 구현하는 것이 Thread 클래스를 사용하는 것보다 더 적절하다.왜냐하면 우리는 스레드를 만들기 위해 Runnable 인터페이스를 구현하면서 다른 클래스를 확장할 수 있기 때문이다.
이게 도움이 되었으면 좋겠어!
한 가지 놀라운 점은 아직 실행이 언급되지 않았다는 것이다.Runnable
수업의 유연성을 향상시킨다.
만약 당신이 스레드를 연장한다면, 당신이 하고 있는 행동은 항상 스레드에 있을 것이다.그러나 구현하는 경우Runnable
그럴 필요 없을 텐데.스레드에서 실행하거나, 어떤 종류의 실행자 서비스에 전달하거나, 스레드된 단일 응용프로그램(나중에 실행되지만 동일한 스레드 내에서 실행될 수도 있음) 내에서 태스크로 전달하면 된다.만약 당신이 단지 사용한다면 옵션은 훨씬 더 개방적이다.Runnable
에 자신을 속박하는 것보다Thread
.
다른 클래스를 구현하거나 확장하려면Runnable
. 그렇지 않으면 다른 클래스를 확장하거나 구현하지 않으려면Thread
수업이 더 좋다.
가장 일반적인 차이점은
당신이 할 때extends Thread
그 수 . 수업은 그 다음에 해야 한다. 수업은 다하다 수업장학 수 있다 (둘 할 수 (자바에서는 아시다시피 둘 이상의 클래스 상속을 허용하지 않는다.)
당신이 할 때implements Runnable
, 당신은 당신의 클래스가 미래 또는 지금 다른 클래스를 확장하기 위해 공간을 절약할 수 있다.
Java는 다중 상속을 지원하지 않으므로, 한 클래스를 Java에서만 확장할 수 있으므로, 일단 Thread 클래스를 확장하면 기회를 놓치고 Java에서 다른 클래스를 확장하거나 상속할 수 없다.
객체 지향 프로그래밍에서 클래스를 확장하는 것은 일반적으로 새로운 기능을 추가하고 동작을 수정하거나 개선하는 것을 의미한다.스레드에서 수정하지 않는 경우 실행 가능한 인터페이스를 사용하십시오.
실행 가능한 인터페이스는 일반 스레드 또는 실행자 또는 다른 수단에 의해 실행될 수 있는 작업을 나타낸다. 따라서 실행 가능한 작업과 스레드 간의 논리적인 분리는 좋은 설계 결정이다.
작업을 실행 가능으로 분리하는 것은 우리가 작업을 재사용할 수 있다는 것을 의미하며, 또한 다른 수단으로부터 작업을 실행할 수 있는 자유가 있다는 것을 의미한다.일단 스레드가 완료되면 스레드를 재시작하십시오.다시 Runnable vs Thread for task, Runnable이 승자다.
Java 디자이너는 Runnable을 Task로 받아들이고 이러한 작업을 실행하는 worker 스레드가 있는 이유와 같은 것을 인식한다.
모든 스레드 방법을 상속하는 것은 실행 가능으로 쉽게 수행할 수 있는 작업을 나타내기 위한 추가 오버헤드일 뿐이다.
자바레 방문으로 인한 예의.blogspot.com
이것들은 자바에서 스레드(Trad)와 런너블(Runnable) 사이의 주목할 만한 차이점들 중 일부였다.스레드 대 런너블의 다른 차이점을 알고 있다면 의견을 통해 공유하십시오.나는 개인적으로 이 시나리오에 대해 Runnable over Thread를 사용하며, 당신의 요구사항에 따라 Runnable 또는 Callable 인터페이스를 사용할 것을 추천한다.
그러나 유의미한 차이는 다음과 같다.
당신이 할 때extends Thread
클래스, 각 스레드는 고유한 객체를 만들고 그것과 연관된다.당신이 할 때implements Runnable
, 동일한 개체를 여러 개의 스레드에 공유한다.
사실 비교하는 것은 현명하지 않다.Runnable
그리고Thread
서로서로
이 두 사람은 마치 멀티스레딩에서처럼 의존성과 관계를 가지고 있다.Wheel and Engine
자동차의 관계.
나는 두 단계로 멀티스레딩을 하는 방법은 하나라고 말하고 싶다.내가 요점을 말하겠다.
실행 가능:
시 구현 시interface Runnable
그것은 당신이 무언가를 창조하고 있다는 것을 의미한다.run able
딴마 로 실 뛸수 것은 이제 스레드 안에서 실행할 수 있는 무언가를 만드는 것은 스레드를 만드는 것을 의미하지 않는다.
그래서 그 학급은MyRunnable
그것은 단지 평범한 클래스일 뿐이다.void run
방법그리고 그 물건들은 오직 방법만을 가진 평범한 물건들이 될 것이다.run
호출될 때 정상적으로 실행될 수 있는 경우(물체를 실로 통과하지 않는 한).
스레드:
class Thread
, 나는 실제로 멀티스레딩을 가능하게 하는 새로운 스레드를 시작할 수 있는 능력을 가진 매우 특별한 클래스라고 말하고 싶다.start()
방법
왜 비교하는 것이 현명하지 않은가?
왜냐하면 우리는 멀티스레딩을 위해 둘 다 필요하기 때문이다.
멀티스레딩을 위해서는 두 가지가 필요하다.
- 스레드(실행 가능) 안에서 실행할 수 있는 것.
- 새로운 스레드(스레드)를 시작할 수 있는 것.
그래서 기술적으로나 이론적으로나 둘 다 실을 시작하는데 필요한데 하나는 달리고 하나는 달린다 (자동차처럼)
그렇기 때문에 실타래를 시작할 수 없는 것이다.MyRunnable
당신은 그것을 의 예에 넘길 필요가 있다.Thread
.
그러나 스레드를 만들고 실행하는 것은 오직class Thread
왜냐하면Thread
를 사용하다Runnable
그래서 우리 모두 알고 있다.Thread
또한 a이다.Runnable
안쪽에
마침내Thread
그리고Runnable
경쟁자나 대체자가 아닌 다중 스레딩에 대해 상호 보완적이다.
실행 가능을 구현해야 하지만, Java 5 이상에서 실행 중인 경우에는 다음 항목으로 시작해서는 안 된다.new Thread
대신 실행 서비스를 사용하십시오.자세한 내용은 다음을 참조하십시오.Java에서 간단한 스레딩을 구현하는 방법.
나는 전문가는 아니지만, 스레드 확장 대신 런너블을 구현해야 할 한 가지 이유를 생각할 수 있다: 자바는 단일 상속만 지원하므로 한 클래스만 연장할 수 있다.
편집: 원래 "인터페이스 구현에는 더 적은 리소스가 필요함"이라고 되어 있었지만, 어느 쪽이든 새 스레드 인스턴스를 생성해야 하므로, 이는 잘못된 것이었습니다.
제3의 방법이 있다고 말하고 싶다.
public class Something {
public void justAnotherMethod() { ... }
}
new Thread(new Runnable() {
public void run() {
instanceOfSomething.justAnotherMethod();
}
}).start();
아마도 이것은 최근에 내가 Javascript와 Actionscript 3을 많이 사용했기 때문에 약간 영향을 받겠지만, 이렇게 하면 당신의 수업은 이와 같이 상당히 모호한 인터페이스를 구현할 필요가 없다.Runnable
.
자바 8이 출시되면서 이제 세 번째 옵션이 생겼다.
Runnable
기능 인터페이스로, 램다 표현식 또는 메서드 참조로 해당 인스턴스가 생성될 수 있음을 의미한다.
예시를 다음으로 대체할 수 있는 항목:
new Thread(() -> { /* Code here */ }).start()
또는 사용하려는 경우ExecutorService
참조:및 : ::
executor.execute(runner::run)
이것들은 당신의 예시보다 훨씬 짧을 뿐만 아니라, 사용의 다른 답변에서 언급된 많은 장점들과 함께 제공된다.Runnable
에 걸쳐서Thread
스레드의 행동을 전문화하지 않기 때문에 단일 책임이나 구성 사용과 같은 것.이렇게 하면 추가 클래스가 생성되는 것을 피할 수 있다.Runnable
예시대로
인터페이스를 인스턴스화하면 코드와 스레드의 구현을 보다 명확하게 구분할 수 있으므로, 이 경우 Runnable을 구현하고 싶다.
스레드 확장과 실행 가능 구현 간의 차이점:
여기 있는 모든 사람들은 Runnable을 구현하는 것이 방법이라고 생각하는 것 같고, 나는 그것들에 별로 동의하지 않지만, 내 의견으로는 Thread를 확장하는 사례도 있다. 사실 당신은 그것을 당신의 코드로 증명했다.
Runnable을 구현하는 경우 Runnable을 구현하는 클래스는 스레드 이름을 제어할 수 없으므로 다음과 같이 스레드 이름을 설정할 수 있는 호출 코드:
new Thread(myRunnable,"WhateverNameiFeelLike");
그러나 스레드를 확장하면 클래스 자체 내에서 이를 관리할 수 있다(예: 스레드의 이름을 '스레드B'로 지정).이 경우 다음을 수행하십시오.
A) 디버깅을 위해 더 유용한 이름을 제공할 수 있음
B)는 해당 클래스의 모든 인스턴스에 해당 이름을 사용하도록 강요하고 있다(실드라는 사실을 무시하고 실행 가능한 것처럼 위와 같이 사용하지 않는 한, 그러나 어떤 경우에도 여기서 관습에 대해 이야기하고 있으므로 내가 느끼는 가능성을 무시할 수 있다).
예를 들어, 생성의 스택 추적을 스레드 이름으로 사용할 수도 있다.이것은 이상하게 보일 수 있지만, 당신의 코드가 어떻게 구성되느냐에 따라 디버깅 목적에 매우 유용할 수 있다.
이것은 작은 일처럼 보일 수 있지만, 여러분이 많은 실과 갑자기 '멈춰진' 것을 가진 매우 복잡한 어플리케이션을 가지고 있는 경우(정착된 이유나 덜 분명할 네트워크 프로토콜의 결함 때문에 또는 또는 다른 끝없는 이유 때문에) 그리고 나서 모든 실들이 있는 Java로부터 스택 덤프를 얻는다.리드 'Thread-1' 'Thread-2' 'Thread-3'는 항상 매우 유용한 것은 아니다(스레드가 어떻게 구조화되고 스택 추적만으로 어떤 것이 어떤 것인지 유용하게 구별할 수 있는지에 따라 달라진다. 동일한 코드를 실행하는 여러 스레드의 그룹을 사용하는 경우 항상 가능한 것은 아니다).
물론 스레드 클래스의 확장명을 생성 호출의 스택 추적으로 설정한 다음 표준 Java 스레드 클래스(아래 참조) 대신 Runnable 구현과 함께 사용하여 일반적인 방법으로 위 작업을 수행할 수 있지만 스택 추적 외에도 더 많은 컨텍스트 사양이 있을 수 있다.디버깅을 위한 스레드 이름(예: 처리할 수 있는 많은 대기열 또는 소켓 중 하나에 대한 참조)에 유용한 fic 정보(예: 컴파일러가 특정 정보(예: 대기열/소켓)를 전달하도록 하기 위해 해당 경우에 대해 스레드를 특별히 확장하는 것을 선호할 수 있음)(질문) 이름에 사용할 수 있는).
호출 스택 추적을 이름으로 하는 일반 스레드의 예는 다음과 같다.
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]
다음 이유 때문에 실행 가능:
- Runnable 구현 시 다른 클래스를 확장할 수 있도록 더 많은 유연성 제공
- 코드 실행과 분리
- 스레드 풀, 이벤트 스레드에서 실행 가능한 실행 가능 또는 향후 다른 방법으로 실행 가능.
지금 이 중 어떤 것도 필요하지 않다고 해도, 미래에는 그럴지도 모른다.스레드를 오버라이드해도 이점이 없기 때문에 런너블이 더 좋은 해결책이다.
이것은 매우 인기 있는 주제고 좋은 답변들이 사방에 퍼지고 아주 깊이 있게 다루어지기 때문에, 나는 다른 사람들의 좋은 답변을 좀 더 간결한 형태로 엮는 것이 정당하다고 느꼈고, 그래서 새로 온 사람들은 쉽게 개괄할 수 있는 선입견을 가지고 있다.
일반적으로 클래스를 확장하여 기능을 추가하거나 수정하십시오.따라서 스레드 동작을 덮어쓰지 않으려면 실행 가능을 사용하십시오.
같은 맥락에서, 만약 당신이 스레드 방법을 상속할 필요가 없다면, 당신은 Runnable을 사용함으로써 그 오버헤드 없이 할 수 있다.
단일 상속:스레드를 확장하는 경우 다른 클래스에서 확장할 수 없으므로, 필요한 경우 실행 가능을 사용하십시오.
도메인 로직과 기술적 수단을 분리하는 것은 좋은 설계인데, 그런 의미에서 실행 가능한 작업을 실행자와 분리하는 것이 더 낫다.
동일한 Runnable 객체를 여러 번 실행할 수 있지만, 스레드 객체는 한 번만 시작할 수 있다.(실행자가 실행 파일을 수락하는 이유일 수 있지만 스레드는 수락하지 않는 이유)
작업을 실행 가능으로 개발하면 현재와 미래에 사용할 수 있는 모든 유연성이 확보된다.실행자를 통해서도 동시에 실행되도록 할 수 있지만 스레드를 통해서도 실행할 수 있다.또한 다른 일반적인 유형/물체와 마찬가지로 동일한 스레드 내에서 현재 사용/불합격이라고 부를 수도 있다.
이렇게 하면 단위 테스트에서 작업 로직과 동시성 측면을 더 쉽게 구분할 수 있다.
만약 당신이 이 질문에 관심이 있다면, 당신은 Callable과 Runnable의 차이에도 관심이 있을 것이다.
이 내용은 Oracle의 Thread 정의 및 시작 튜토리얼에 설명되어 있다.
이 숙어 중 어떤 것을 사용해야 하는가?Runnable 개체를 사용하는 첫 번째 숙어는 Runnable 개체가 Thread 이외의 클래스를 하위 분류할 수 있기 때문에 더 일반적이다.두 번째 숙어는 단순한 응용 프로그램에서는 사용하기 더 쉽지만, 당신의 작업 클래스가 스레드의 후손이어야 한다는 사실에 의해 제한된다.이 과정에서는 작업을 실행하는 스레드 개체와 실행 가능한 작업을 구분하는 첫 번째 접근 방식에 초점을 맞춘다.이 접근방식은 보다 유연할 뿐만 아니라 나중에 다루는 고급 스레드 관리 API에도 적용할 수 있다.
, 즉, 구를 하는 것이다Runnable
클래스가 다른 클래스를 확장하는 시나리오에서 작동함Thread
Java는 다중 상속을 지원하지 않는다., 연장.Thread
일부 높은 수준의 스레드 관리 API를 사용할 때는 불가능할 것이다.확장되는 유일한 시나리오Thread
향후 업데이트의 대상이 되지 않는 소규모 응용 프로그램에 있는 것이 바람직하다.구현하는 것이 거의 항상 더 낫다.Runnable
에서 많은 할 수 한 만 연장할 수 큰 것이다많은 인터페이스를 자바에서 구현할 수 있지만 하나의 클래스만 확장할 수 있기 때문에 설계 변경은 큰 영향을 미치지 않을 것이다.
가장 간단한 설명은 구현하는 것이다.Runnable
우리는 동일한 대상을 여러 개의 스레드에 할당할 수 있고, 각각Thread
동일한 개체 상태 및 동작을 공유한다.
예를 들어, 두 개의 스레드가 있다고 가정하면, 스레드1은 배열에 정수를 넣고, 스레드2는 배열이 채워질 때 배열에서 정수를 가져간다.스레드2가 작동하려면 스레드1이 채워졌는지 여부에 따라 배열 상태를 알아야 한다는 점에 유의하십시오.
구 Runnable
이와 달리 개체를 공유할 수 있는 유연성 제공extends Thread
각 스레드에 대해 새 객체를 만들 수 있으므로 스레드1에 의해 수행된 모든 업데이트는 스레드2에 손실된다.
내가 틀리지 않았다면 어느 정도는 비슷할 것이다.
확장자는 "Is A" 관계를 설정하며 인터페이스는 "Has a" 기능을 제공한다.
실행 가능한 구현 선호:
- 스레드 클래스를 확장하고 스레드 API 기본 구현을 수정할 필요가 없는 경우
- 화재 발생 시 명령을 잊어버린 경우
- 다른 클래스를 이미 확장하는 경우
"확장 스레드" 선호:
- Oracle 설명서 페이지에 나열된 스레드 메서드를 재정의해야 하는 경우
일반적으로 스레드 행동을 무시할 필요는 없다.따라서 대부분의 경우 Runnable 구현이 선호된다.
를 사용하려고 한다.ExecutorService
또는ThreadPoolExecutorService
API는 더 많은 유연성과 제어력을 제공한다.
다음 SE 질문을 살펴보십시오.
실행 가능 구현에서 스레드 클래스를 분리하면 스레드 및 실행() 방법 간의 잠재적인 동기화 문제도 방지할 수 있다.별도의 Runnable은 일반적으로 Runnable 코드가 참조되고 실행되는 방식에 더 큰 유연성을 제공한다.
Runnable
인터페이스인 반면Thread
이 인터페이스를 구현하는 클래스.설계 관점에서, 업무 정의 방법과 업무 수행 방법 사이에는 깨끗한 분리가 있어야 한다.이다.Runnalbe
구현, 그리고 후자는 작업이다.Thread
수업을 대부분의 경우 구현Runnable
옳은 방법이야
스레드는 코드의 비동기 실행 컨텍스트(실행 컨텍스트: 스택 프레임, 스레드 ID 등)를 구현한다.그 코드 조각은 이상적으로는 동기식이든 비동기식이든 동일한 구현이어야 한다.
한 구현에서 이러한 요소를 함께 묶는 경우 결과 개체에 관련 없는 두 가지 변경 원인을 제공하십시오.
- 응용프로그램의 스레드 처리(즉,실행 컨텍스트 쿼리 및 수정)
- 코드 조각에 의해 구현된 알고리즘(실행 가능한 부분)
사용하는 언어가 부분 클래스나 다중 상속을 지원하는 경우 각각의 원인을 자체 슈퍼 클래스에서 분리할 수 있지만, 특징 집합이 겹치지 않기 때문에 두 객체를 구성하는 것과 같은 것으로 요약된다.그것은 이론에 대한 것이다.
일반적으로 말하면, 프로그램은 필요 이상으로 복잡할 필요가 없다.특정 태스크에 대해 하나의 스레드를 사용하는 경우 해당 태스크를 변경하지 않고 태스크를 별도의 클래스로 만들 필요가 없으며 코드가 더 단순해짐
자바(Java)의 맥락에서, 설비는 이미 거기에 있기 때문에, 아마도 단독적으로 직접 시작하는 것이 더 쉬울 것이다.Runnable
수업하고, 그 예시를 에 전하다.Thread
(또는)Executor
) 인스턴스.일단 그 패턴에 익숙해지면, 간단한 런너블 스레드 케이스보다 사용(또는 읽기도)하기가 어렵지 않다.
기본 클래스를 확장하는 대신 인터페이스를 구현하려는 한 가지 이유는 이미 다른 클래스를 확장하고 있기 때문이다.클래스는 하나만 확장할 수 있지만, 인터페이스 수는 얼마든지 구현할 수 있다.
스레드를 확장하면 기본적으로 '이것'이 아닌 다른 스레드에 의해 논리가 실행되는 것을 방지하는 것이다.자신의 논리를 실행할 스레드만 원하면 Runnable을 구현하는 것이 좋다.
런너블을 사용하면 다른 클래스로 확장하기 위해 공간을 절약할 수 있다.
우리 반이 학생답게 행동하기를 원했던 기본적인 이유를 다시 한번 찾아볼 수 있을까?Thread
단지 은 작업 를 기다릴 수 기다릴 수 의 여부를 아무런 이유도 없이, 우리는 비동기 모드에서 작업을 실행하려고 했을 뿐인데, 이는 작업 실행이 조기에 완료되거나, 분기된 경로(태스크)를 기다릴 수 있거나, 기다릴 수 없는 경우 정확히 우리의 메인 스레드와 메인 스레드에서 분기되어야 한다는 것을 의미한다.
이것이 전체 목적이라면, 전문화된 스레드의 필요성은 어디에서 볼 수 있는가?이 작업은 시스템의 스레드 풀에서 RAW 스레드를 선택하고 이 스레드에 우리의 과제(일 수 있음)를 할당하는 것으로 수행될 수 있으며, 그것이 바로 우리 클래스의 한 예일 수 있다.
그러므로 OOPs 개념을 준수하고 우리가 필요로 하는 유형의 수업을 쓰도록 하자.일을 하는 데는 여러 가지 방법이 있는데, 옳은 방법으로 하는 것이 중요하다.
우리는 과제가 필요하니 스레드에서 실행할 수 있는 작업 정의를 쓰세요.그러니까 런너블을 쓰세요.
항상 기억하라implements
행동의 전달에 특히 사용되었고extends
특징/특징을 전달하기 위해 사용된다.
우리는 실의 소유물을 원하지 않고, 대신 우리는 우리 반이 실행될 수 있는 과업으로 행동하기를 원한다.
예, ThreadA 호출을 호출하는 경우 시작 메소드를 호출할 필요가 없으며 실행 메소드는 TradA 클래스만 호출한 후 호출하십시오.그러나 ThreadB 호출을 사용할 경우, 호 실행 방법에 대한 시작 스레드가 필요하다.도움이 더 있으면 답장해줘.
언급된 모든 이유로 Runnable을 사용하는 것이 가장 유용하다는 것을 알게 되었지만, 때때로 나는 스레드 확장을 좋아해서 나만의 스레드 정지 방법을 만들어 내가 만든 스레드 위에서 직접 호출할 수 있다.
Java는 다중 상속을 지원하지 않으므로 스레드 클래스를 확장하면 다른 클래스가 확장되지 않는다.
예:애플릿을 만들면 애플릿 클래스를 확장해야 하므로 여기서 스레드를 만드는 유일한 방법은 실행 가능한 인터페이스를 구현하는 것이다.
스레드와 실행 가능 간의 차이.만약 우리가 스레드 클래스를 사용하여 스레드를 만든다면, 스레드 수는 우리가 만든 객체 수와 같다. 만약 우리가 실행 가능한 인터페이스를 구현하여 스레드를 만든다면, 우리는 여러 스레드를 만들기 위해 단일 객체를 사용할 수 있다.그래서 단일 개체는 여러 스레드에 의해 공유된다.그래서 기억이 덜 걸릴 것이다.
따라서 우리의 데이터가 노지향적이지 않은지 요건에 따라 달라진다.실행 가능한 인터페이스를 사용할 수 있는 여러 스레드 간에 공유할 수 있다.
여기에 내 2센트 추가하기 - 가능하면 언제든지 사용하라. 아래에는 s를 사용해서는 안 되는 이유에 대한 두 가지 주의사항이 있다.
이상적으로는 스레드 클래스를 확장하지 마십시오.
Thread
수업이 이루어져야 한다.final
적어도 그 방법은 다음과 같다.thread.getId()
확장 관련 버그는 이 토론을 참조하십시오.Thread
s. s퍼즐을 푸는 것을 좋아하는 사람들은 스레드를 연장하는 또 다른 부작용을 볼 수 있다.아래 코드는 아무도 알리지 않을 때 연결할 수 없는 코드를 출력할 것이다.
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 ");
}
}
}
참조URL: https://stackoverflow.com/questions/541487/implements-runnable-vs-extends-thread-in-java
'programing' 카테고리의 다른 글
값을 vue 인스턴스에 전달하는 방법? (0) | 2022.04.20 |
---|---|
V-툴팁:메서드에서 팝업 닫기 (0) | 2022.04.20 |
랜드()를 사용할 때 이 특정 색상 패턴을 얻는 이유는? (0) | 2022.04.20 |
람다를 연재하는 방법? (0) | 2022.04.20 |
sprintf/snprintf 중 어느 것이 더 안전한가? (0) | 2022.04.20 |