1. Create a thread
When talking about thread creation, there are always several keywords in my mind: runnable and thread; but what is the relationship between them?
1. runnable: the purpose of creating a thread is to execute a task or a piece of business logic. So how can we notify the System of the tasks to be executed? The answer is: implement the run method of the runnable interface and write the business logic to it.
(We can compare the run method in runnable to a "task Proposal". Now we just wrote a report and haven't found a specific thread (like an employee) for execution)
2. Thread: The Task Drive (or the employee who executes the task plan). For this drive, we only need to learn one of its constructor methods and one static method.
(1) The source code implementation of the constructor is:
public Thread(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0); }
In this constructor, only one thing is to call the thread member function init.
Private void Init (threadgroup g, runnable target, string name, long stacksize) {/* omitting a piece of unreadable Code */This. group = g; this. daemon = parent. isdaemon (); this. priority = parent. getpriority (); this. name = Name. tochararray (); If (SECURITY = NULL | isccloverridden (parent. getclass () This. contextclassloader = parent. getcontextclassloader (); else this. contextclassloader = parent. contextclassloader; this. inheritedaccesscontrolcontext = accesscontroller. getcontext (); this.tar get = target; setpriority (priority);/* then omit a piece of unreadable Code */}
In summary, we can see that when we use the statement thread mythread = new thread (target), [here, the target is the "task Proposal" that implements the runnable interface "], thread actually helps us do a lot of initialization work that must be done to create a thread, for example:
A. Give the thread a unique name: "thread-" + nextthreadnum ()
B. Set the thread priority.
C. Set whether the thread is daemon. The thread is a daemon thread.
D. Set the Class Loader for the thread.
And so on.
Well, this is the most important construction method of thread. Next let's look at the thread startup method: thread. Start ()
(2) thread. Start (), first paste the source code of start:
public synchronized void start() { ... boolean started = false; try { start0(); started = true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { .. } } }
private native void start0(); @Override public void run() { if (target != null) { target.run(); } }
Oh, it turned out to be a waste of time for half a day. start () ≈ runnable. run (), as to why we want to design it like this, we will mention the software engineering or the software design model we have learned, to put it bluntly, we try to decouple the program when writing the program. By programming the interface, we can make the unstable part of the system depend on the stable part. In this way, when the unstable part changes, the stable part does not need to be changed, thus facilitating program expansion.
After writing this, we can create and start a thread to run it. paste a simple example to consolidate what we learned above:
Step 1: implement the runnable interface and run method (develop the "task book")
public class MyThread2 implements Runnable{@Overridepublic void run() {for(int i = 0 ; i < 10; i ++){System.out.println("myThread1 said : "+i+" ");}}}
Step 2: Pass the instance that implements the runnable interface to the task drive thread and call the thread. SART method to enable the thread.
public static void main(String args[]){Thread myThread = new Thread(new MyThread1());myThread.start();for( int i = 0 ; i < 10; i++){System.out.println("main said : "+i+" ");}}
3. Using the preceding runnable and thread to create a thread cannot return results. What if I have to return a result? Write a class that implements the callable interface.
(1) callable is similar to runnable. It is just an interface that declares only one method. Let's take a look at its specific definition:
public interface Callable<V> { V call() throws Exception;}
Well, that's right. The definition of callable is so simple.
V indicates the type of the result to be returned.
The only difference between creating a thread using callable and using runnable is that the function we want to implement is different. One is call and the other is run.
Therefore, I will write a small demo here. There is nothing else to talk about:
Step 1: Write a class that implements the callable interface and implement its call Method
public class MyThread1 implements Callable <String>{@Overridepublic String call() throws Exception {int sum = 1;for(int i=1; i <= 3;i++){sum *= i;}TimeUnit.MILLISECONDS.sleep(10);return ""+sum;}}
Step 2: Pass the Instance Object of the above class to executorservice. Submit (callable <string> mythread1). [why do you want to do this here? I will explain it below]
public class Test{public static void main(String args[]) throws InterruptedException, ExecutionException{ExecutorService exec = Executors.newCachedThreadPool();Future<String> f = exec.submit(new MyThread1());int i = 0;while(true){i++;if(f.isDone()){System.out.println("result from thread is :"+f.get().toString());break;}System.out.println("main said : "+i);}}}
It is necessary to explain future here. Future is actually a design model. Let's briefly describe it:
As its name implies, future is something of the future. It is a generic type used to install results that may not exist. For example, thread a wants to obtain the result after line B is run, however, there may be a situation where the returned results of line B are still being calculated, or the computation is being sent to thread a through the network. At this time, a has two attitudes towards B's results.
I. I hope to see this object available and complete some related subsequent processes. If it is unavailable, you can also go to another branch process.
Ii. "Without you, my life will lose its meaning, so even if the sea breaks down, I will wait for you ".
For attitude I, you can use future. isdone to determine whether the result of B can be obtained.
For attitude II, you need to use future. Get (). After using this method, thread a will block and know that the result of B is obtained.
This is the first step in thread creation. In the next section, we will learn how to use executor to manage threads !!!