This article was first published on Uncle Cat’s blog
preface
Concurrency is a wonderful thing, scheduling and using threads gives you a new world view beyond business code, whether you’re involved or not, but it helps you grow in the future.
So, let’s take a closer look at a few ways to start threads in Java.
Thread
The Java virtual machine (JVM) allows applications to run multiple threads of execution simultaneously. And this Thread is the program’s execution Thread.
How to use it, in fact, the source code in this class has been written for us, even the use of Runnable below. (Thread source code)
/** * A thread is a thread of execution in a program. The Java * Virtual Machine allows an application to have multiple threads of * execution running concurrently. *
* class PrimeThread extends Thread { * long minPrime; * PrimeThread(long minPrime) { * this.minPrime = minPrime; * } * * public void run() { * // compute primes larger than minPrime * . . . * } * } *
*
* The following code would then create a thread and start it running: *
* PrimeThread p = new PrimeThread(143); * p.start(); **
*
* class PrimeRun implements Runnable { * long minPrime; * PrimeRun(long minPrime) { * this.minPrime = minPrime; * } * * public void run() { * // compute primes larger than minPrime * . . . * } * } *
*
* The following code would then create a thread and start it running: *
* PrimeRun p = new PrimeRun(143); * new Thread(p).start(); **
*/
public class Thread implements Runnable {
/ /...
}
Copy the codeRead the source information is actually the most complete, I intercepted part of the comment information, at least we can now use this two ways to start their own threads without pressure.
If we want to pass arguments, we can create our own constructor as follows:
public class MyThread extends Thread { public MyThread(String name) { super(name); } @Override public void run(a) { System.out.println("A child thread BY"+ getName()); }}Copy the code
Threads in Java have their own names, and if we don’t define a name for them, Java will give them their own names.
/** * Allocates a new {@code Thread} object. This constructor has the same * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} * {@code (null, null, name)}. * * @param name * the name of the new thread */ public Thread(String name) { init(null.null, name, 0); } Copy the code
And the most important thing that we care about is how to start and execute our thread, and yes, we all know that, that’s the run method.
And if you’re familiar with Runnable, I think you’ll know that the run method is actually a Runnable method, and that Thread implements that interface in this section.
Here, you might wonder, shouldn’t it be the start method? So let’s look at the source of start.
/** * Causes this thread to begin execution; the Java Virtual Machin * calls the
run
method of this thread. */ public synchronized void start(a) { / /... } Copy the codeThe start method will cause the Java virtual machine to call the thread’s run method, just as in the source code’s start template.
As a result, one thread runs the start method and another thread runs the run method. As for such threads, Java officials also say that threads are not allowed to start more than once, which is illegal.
So if we execute the following code, will be submitted to the Java. Lang. IllegalThreadStateException anomalies.
MyThread myThread = new MyThread("Thread"); myThread.start(); myThread.start(); Copy the code
But what about code like this?
MyThread myThread = new MyThread("Thread"); myThread.run(); myThread.run(); myThread.start(); // Run the resultChild Thread BY Thread One child Thread BY Thread one child Thread BY ThreadCopy the code
This is not reasonable, if you are interested, you can try and test it, preferably in debug mode.
Thread_runnable (thread_runnable, thread_runnable, thread_runnable)
Runnable
I’d like you to use the Runnable interface more than Thread, but I’ll talk about the pros and cons in the conclusion.
I think the source of Runnable will be easier to read and accept, after all, it has a run method. (Below is the source code)
/** * The
Runnable
interface should be implemented by any * class whose instances are intended to be executed by a thread. The * class must define a method of no arguments calledrun
. */ @FunctionalInterface public interface Runnable { /** * When an object implementing interfaceRunnable
is used * to create a thread, starting the thread causes the object's *run
method to be called in that separately executing * thread. */ public abstract void run(a); } Copy the codeFirst, all classes that intend to execute threads can implement the Runnable interface and must implement the Run method.
It will provide a protocol for each class, just like Thread. In fact, when our class implements the Runnable interface, our class will be the same class as Thread, except that it may only have the run method, but not the rich functionality provided by Thread.
In the case of the run method, all classes that implement the Runnable interface will be made to execute the run method separately after calling start.
So we can write test code like this.
MyThreadRunnable myThreadRunnable = new MyThreadRunnable("Runnabel"); myThreadRunnable.run(); new Thread(myThreadRunnable).start(); Thread thread = new Thread(myThreadRunnable); thread.start(); thread.start(); // Run effect Exception in thread "main" java.lang.IllegalThreadStateException at java.lang.Thread.start(Thread.java:705) at com.github.myself.runner.RunnableApplication.main(RunnableApplication.java:14This is a child thread BY RunnabelCopy the code
Similarly, threads are not allowed to be started more than once, which is illegal.
At the same time, we see the difference between using Thread and Runnable when we want to enable the same function multiple times.
I think Runnable is more for you.
However, using these two methods, how do we know the result of the thread?
FutureTask
This is probably not used by many people (beginners), but this is what I’m most interested in right now. It’s interesting.
In fact, there is a little brother, Callable. They are a pair. If you’ve read the above, you’ve probably already found Callable.
Yes, it appears in Runnable’s source code.
/ * * *@author Arthur van Hoff * @see java.lang.Thread * @see java.util.concurrent.Callable * @sinceJDK1.0 * / @FunctionalInterface public interface Runnable {} Copy the code
So let’s take a look at this Callable. (Below is the source code)
/** * A task that returns a result and may throw an exception. * Implementors define a single method with no arguments called * {@code call}. */ @FunctionalInterface public interface Callable<V> { /** * Computes a result, or throws an exception if unable to do so. * * @return computed result * @throws Exception if unable to compute a result */ V call(a) throws Exception; } Copy the code
In fact, this is basically the same interface as Runnable, in that it can return execution results and check for exceptions, the results of which are returned by the call() method.
So we can actually write an implementation class now.
public class MyCallable implements Callable { private String name; public MyCallable(String name) { this.name = name; } @Override public Object call(a) throws Exception { System.out.println("This is a child thread BY." + name); return "successs"; }}Copy the code
I’ll save that for the next article.
Ok, I think it’s time to look at the FutureTask class.
/** * A cancellable asynchronous computation. This class provides a base * implementation of {@link Future}, with methods to start and cancel * a computation, query to see if the computation is complete, and * retrieve the result of the computation. The result can only be * retrieved when the computation has completed; the {@code get} * methods will block if the computation has not yet completed. Once * the computation has completed, the computation cannot be restarted * or cancelled (unless the computation is invoked using * {@link #runAndReset}). */ public class FutureTask<V> implements RunnableFuture<V> { / /... } Copy the code
The source code makes it clear that this is an asynchronous computation that can be cancelled, providing methods for querying, calculating, viewing results, etc., and we can also use runAndRest to restart the computation.
When we look at its constructor, we are glad to see our Callable interface.
/** * Creates a {@code FutureTask} that will, upon running, execute the * given {@code Callable}. * * @param callable the callable task * @throws NullPointerException if the callable is null */ public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; // ensure visibility of callable } Copy the code
That is, we will create a future task to execute the implementation class of Callable. So now we can write code like this.
final FutureTask fun = new FutureTask(new MyCallable("Future")); Copy the code
So then we can run our task?
Yes, I know the run() method, but I don’t have the start method.
Since the official said there was a result, so I found the get method. I also tried to write some test code.
public static void main(String[] args) { MyCallable myCallable = new MyCallable("Callable"); final FutureTask fun = new FutureTask(myCallable); fun.run(); try { Object result = fun.get(); System.out.println(result); } catch (InterruptedException e) { e.printStackTrace(); } catch(ExecutionException e) { e.printStackTrace(); }}Copy the code
It works, it works, it seems to work.
// Run effectThis is a child thread BY Callable SuccesssCopy the code
However, as I tried to add more code, I discovered something wonderful.
I added a line of fun.run(); Code, meanwhile, in the MyCallable class, adds a time thread to the method to wait for 3s.
The result is that the result is output only once, and the get method needs to wait for 3s before returning.
That’s not what I want to see. But at least we know that even though we run the run method multiple times, the thread only runs once. This is good news.
At the same time, we also got the result of the task when our progress was blocked and we had to wait for our task to complete.
Finally, after a little research, the following code does what we expected.
public static void main(String[] args) { MyCallable myCallable = new MyCallable("Callable"); ExecutorService executorService = Executors.newCachedThreadPool(); final FutureTask fun = new FutureTask(myCallable); executorService.execute(fun); // fun.run(); // Block the process System.out.println("-- Continue execution"); try { Object result = fun.get(); System.out.println(result); } catch (InterruptedException e) { e.printStackTrace(); } catch(ExecutionException e) { e.printStackTrace(); }}Copy the code
We use the thread pool to run our FutureTask and use the GET method to get the results of the run. The result is friendly and the process does not block.
I’ll save that for the next article.
Conclusion a wave
Okay, now it’s time to sort this out.
- Thread needs to be inherited, which is limited because Java’s inherited resources are limited and the task class needs to be created multiple times if the task is executed multiple times.
- RunnableIt is convenient for us to implement it in the form of an interface. There is no need to create multiple task classes for executing tasks simultaneously. At that time, there was only one task
run
Methods. - FutureTask can obtain the task execution result. There are also more new features that make it easier to use
Public number: Java cat said
Now architecture designer (code farmer) and entrepreneurial technology consultant, unruly mediocre, love open source, talk about program life and irregular dry goods.