List of articles
-
- introduction
- There are three ways to create a thread
- One 、 Inherit Thread class
- Two 、 Realization Runnable Interface
- 3、 … and 、 Use Callable and Future Create thread
- Three ways to compare
introduction
In daily development work , Multi-threaded development can be said to be a necessary skill , A good programmer must have an in-depth understanding of threads , I am a Java The programmer , also Java The language itself has very sophisticated support for thread development , So today we’re going to walk in the door , Learn to look Java How to create threads .
There are three ways to create a thread
Java There are three main ways to create threads :
1、 Inherit Thread class
2、 Realization Runnable Interface
3、 Use Callable and Future Create thread
The following sections discuss how each of these methods is implemented , And the contrast between them .
One 、 Inherit Thread class
step :
1、 Creates a thread subclass inheritance Thread class
2、 rewrite run() Method , Put in programs that require threads to execute run Method , The program in the method runs after the thread starts
2、 Create an instance of this class , And call the object’s start() Method to start the thread
The sample code is as follows :
public class ThreadDemo extends Thread{
@Override
public void run() {
super.run();
System.out.println(" The program that needs to be run ........");
}
public static void main(String[] args) {
Thread thread = new ThreadDemo();
thread.start();
}
}
When running main After the method , The program will execute run() The contents of the method , After execution , Threads die with them , Why do I have to rewrite it run() Methods? ?
After clicking the source of the method , Find out Thread Of run() The method doesn’t actually do anything, right
public void run() {
if (target != null) {
target.run();
}
}
public abstract void run();
If run() There is no program to run , Then the thread just dies when it starts . You have to override the thread to do something, right run() Method . meanwhile , The other thing to note is that , Thread startup requires a call start() Method , But call directly run() Methods can also be compiled , It works :
public static void main(String[] args) {
Thread thread = new ThreadDemo();
thread.run();
}
It’s just a normal method call , There is no new thread started , It loses the meaning of the thread itself .
Two 、 Realization Runnable Interface
1、 Defines a thread class implementation Runnable Interface , Override the interface run() Method , The method is still the one that contains the specified execution .
2、 Create a Runnable Implementation class instance , Regard it as target Parameters of the incoming , And create Thread Class instance .
3、 call Thread Class instance start() Method to start the thread .
public class RunnableDemo implements Runnable{
@Override
public void run() {
System.out.println(" I am a Runnable Interface ......");
}
public static void main(String[] args) {
RunnableDemo demo = new RunnableDemo();
Thread thread = new Thread(demo);
thread.start();
}
}
This is the interface based approach , Compared to inherit Thread Be much more flexible , But you need to create an additional thread object , Open source can be found , When put Runnable An instance of the implementation class as an argument target After the incoming , Assigned to the current thread class target, and run() The program that executes in is assigned to it target Of run() Method .
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc) {
........... Part of the source code is omitted here ..........
this.target = target;
setPriority(priority);
if (parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
tid = nextThreadID();
}
@Override
public void run() {
if (target != null) {
target.run();
}
}
3、 … and 、 Use Callable and Future Create thread
Use Callable Create threads and Runnable The interface way to create threads is similar , The difference is ,Callable The interface provides one call() Method as the body of the thread execution , and Runnable What the interface provides is run() Method , meanwhile ,call() Methods can have return values , And you need to use FutureTask Class to packaging Callable object .
public interface Callable<V> {
V call() throws Exception;
}
step :
1、 establish Callable Implementation class of interface , Realization call() Method
2、 establish Callable Implementation class instance , adopt FutureTask Class to packaging Callable object , The object is encapsulated Callable Object’s call() Return value of method .
3、 Will create the FutureTask Object as target Parameters of the incoming , establish Thread Thread instance and start a new thread .
4、 call FutureTask Object’s get Method gets the return value .
public class CallableDemo implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int i = 1;
return i;
}
public static void main(String[] args) {
CallableDemo demo = new CallableDemo();
FutureTask<Integer> task = new FutureTask<Integer>(demo);
new Thread(task).start();
try {
System.out.println("task The return value is :" + task.get());
} catch (Exception e) {
e.printStackTrace();
}
}
}
perform main After the method , The program outputs the following results :
task The return value is :1
explain ,task.get() Did return call() Result of method . So how does it work internally . To open the first FutureTask Construction method of , You can see that the interior is going to be Callable Object passed to the current instance as a parameter Callable member ,
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
meanwhile , Member variable state Set as NEW, When to start task after , Its run Method will be executed Callable Of call() Method ,
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
// hold call() The return result is copied to result
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
// Set the result to another variable
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
// Assign the passed value to outcome member
outcome = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
run() Method after a series of programs run , hold call() The return result is assigned to outcome, And then when called task.get() That’s what you get in the method outcome The value of the , thus , So we get the return result .
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
private V report(int s) throws ExecutionException {
Object x = outcome;
if (s == NORMAL)
// return outcome Value
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}
It can be seen that , The running logic of the source code is relatively clear , The code is also easier to understand , therefore , I’d rather suggest that readers take a look at it when they have time Java Underlying source code , This will give us a deeper understanding of how functionality is implemented .
Three ways to compare
Okay , All three ways to create an instance of a thread are covered , Here’s how they compare .
In terms of implementation , Use Runnable Interface and Callable The way the interface works is basically the same , It’s just that Callable The implemented method body can have a return value , And inheritance Thread Classes use inheritance , therefore , In fact, the three methods can be divided into two categories for analysis .
1、 Using inheritance Thread Kind of the way :
- advantage : The coding is simple , also , When required to get the current thread , It can be used directly this
- Inferiority : because Java Support single inheritance , So the inheritance Thread You cannot inherit from any other parent class
2、 Use Runnable Interface and Callable How to interface :
- advantage :
More flexible , Threads simply implement the interface , You can also inherit from other parent classes .
In this way , Multiple threads can share one target object , It is ideal for multithreading the same resource .
Callable The interface also gets the return value .
- Inferiority :
The code is a little bit more complicated , More objects need to be created .
If you want to access the current thread , Need to use Thread.currentThread() Method .
in general , Both categories have their advantages and disadvantages , But the latter’s comparative advantages are negligible , In general , It is also recommended that threads be created directly using interfaces , After all, the disadvantages of single inheritance are large .