1. Invariant ways of java thread creation and start-up
public class TestThread implements Runnable{
public void run(){
//out("hello..")
}
}
Thread thread = new Thread(TestThread);
thread.start();
2. How does Executors manage and start threads in a pooled manner?
Taking the new Fixed ThreadPool method as an example, the ExecutorService object is
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
The meaning and usage of the parameters are as follows:
if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = ctl.get(); } if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); if (! isRunning(recheck) && remove(command)) reject(command); else if (workerCountOf(recheck) == 0) addWorker(null, false); } else if (!addWorker(command, false)) reject(command);
Explanation: First use coreSize, then queue, queue, then maxSize, then full, then reject
Typically, ThreadFactory and Rejected Execution Handler use the default (or freely implemented)
The default ThreadFactory is as follows:
static class DefaultThreadFactory implements ThreadFactory { private static final AtomicInteger poolNumber = new AtomicInteger(1); private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; DefaultThreadFactory() { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-"; } public Thread newThread(Runnable r) { Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); if (t.isDaemon()) t.setDaemon(false); if (t.getPriority() != Thread.NORM_PRIORITY) t.setPriority(Thread.NORM_PRIORITY); return t; } }
This includes the naming of thread names and the creation of Thread objects (new Thread) for thread pools.
3. What did submit do?
Look at this class first.
Methods includepublic abstract class AbstractExecutorService implements ExecutorService
as well aspublic Future<?> submit(Runnable task) { if (task == null) throw new NullPointerException(); RunnableFuture<Void> ftask = newTaskFor(task, null); execute(ftask); return ftask; }
public <T> Future<T> submit(Callable<T> task) { if (task == null) throw new NullPointerException(); RunnableFuture<T> ftask = newTaskFor(task); execute(ftask); return ftask; }
Whether submit is Runnable or Callable, it is converted to FutureTask objects
Two important fields
/** The underlying callable; nulled out after running */ private Callable<V> callable; /** The result to return or exception to throw from get() */ private Object outcome; // non-volatile, protected by state reads/writes
Use callable to store unnable or Callable submit s
Look at the two interfaces implemented by FutureTask, Runnable, Future
Among them, the implementation of run method is as follows:
try { result = c.call(); ran = true; } catch (Throwable ex) { result = null; ran = false; setException(ex); } if (ran) set(result);
The point is to call the call method in Callable and set(result) to put the result into outcom. Through the get() operation of FutureTask, the outcom result after left is obtained.
4. Look back at how threads start()
When the core Size is smaller than the pool, the key code in the method addWorker (Runnable first Task, Boolean core) like ThreadPoolExecutor is as follows:
final Thread t = w.thread; if (t != null) { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { // Recheck while holding lock. // Back out on ThreadFactory failure or if // shut down before lock acquired. int rs = runStateOf(ctl.get()); if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) { if (t.isAlive()) // precheck that t is startable throw new IllegalThreadStateException(); workers.add(w); int s = workers.size(); if (s > largestPoolSize) largestPoolSize = s; workerAdded = true; } } finally { mainLock.unlock(); } if (workerAdded) { t.start(); workerStarted = true; } }
Among them, the t object is the thread created by DefaultThreadFactory above. Looking at the following code, the t.start() is executed.
Another concern is workers.add(w), which is a collection of pool-maintained threads of HastSet type.
5. Summarize
(1) DefaultThreadFactory is used to create threads that actually execute
(2) ThreadPool Executor is used to maintain pools, queues, execution threads, etc.
(3) FutureTask is the ultimate task performed by threads in the pool (i.e. the class that implements Runnable). It also has another responsibility, which is to store and return the results of.get().
(4) TestThread created by users themselves, whether Runnable or Callable, is eventually converted to Callable and executed in the run method of FutureTask.
6. Welcome to correct mistakes, I will continue to add.