Yun Zhihui (Beijing) Technology Co., Ltd. Chenxin
Yes. A thread cannot be started two times. So how does it come to be inferred?
Public synchronized void Start () {
/**
* A Zero status valuecorresponds to State "NEW". 0 The corresponding is state NEW
*/
if (threadstatus!= 0)//Assuming it is not new state, throw an exception directly!
Throw Newillegalthreadstateexception ();
Group.add (this);
Boolean started = false;
try {
Start0 (); Native methods for starting threads
started = true;
} finally {
try {
if (!started) {
Group.threadstartfailed (this);
}
} catch (Throwable ignore) {
}
}
}
Well, only the new state can invoke the native method to start a thread. All right. Got here. In popularity also self-complements the thread state in the JVM:
Full thread state::
L new--hasn't started yet.
L runnable--is executing on the JVM.
L blocked--is waiting for the lock/semaphore to be released
L waiting--wait for a specific action on one of the other threads
L TIMED_WAITING--A Thread, iswaiting for another, thread to perform an action for up to A specified waitingtime are in This state.
L terminated--exit, stop
A thread may have only one state at a point in time. These states are in the JVM and do not reflect the state of the operating system threads. Check the thread API and there is no API to change its state. So this is a way out of line?
Take a careful look at ...
Assume that the task is made into a runnable implementation class, and then, before throwing the implementation class into the thread pool scheduler, use this runnable to construct a thread that is not the thread object that controls this Runnable object. And then control the task that executes in the thread pool? Not too! Let's take a look at thread and Threadpoolexecutor to runnable.
Thread
/* What would berun. */
Private Runnabletarget;
In combination with the start () method above, it is very easy to guess that start0 () will make the target into a thread for execution.
Threadpoolexecutor
public void execute (Runnable command) {
if (command== null)
Thrownew Nullpointere Xception ();
int c =ctl.get ();
if (Workercountof (c) < corepoolsize) {
if (addworker (command, True))
return;
C =ctl.get ();
}
if (IsRunning (c) && workqueue.offer (command)) {
Intrecheck = Ctl.get ();
if (!isrunning (recheck) && Remove (command))
Reject (command);
Else if (workercountof (recheck) = = 0)
Addworker (null, FALSE);
}
Else if (!addworker (command, false))
Reject (command);
}
Private Boolean Addworker (Runnablefirsttask, Boolean core) {
...
booleanworkerstarted = false;
booleanworkeradded = false;
Worker W =null;
try {
Finalreentrantlock mainlock = This.mainlock;
W = Newworker (firsttask);
Finalthread t = w.thread;
if (t!= null) {
Mainlock.lock ();
try{
int c = Ctl.get ();
int rs = runstateof (c);
if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) { if (t.isAlive()) // precheck that t is startable throw newIllegalThreadStateException();
Workers.add (w);
int s = workers.size ();
if (S > Largestpoolsize)
Largestpoolsize =s;
Workeradded = true;
}
}finally {
Mainlock.unlock ();
}
if (workeradded) {
T.start ();
Workerstarted = true;
}
}
} finally {
if (!workerstarted)
Addworkerfailed (w);
}
return workerstarted;
}
So what about the worker?
Worker
Private Final Class Worker
Extendsabstractqueuedsynchronizer
Implementsrunnable
{
Finalthread thread;
Runnablefirsttask;
Volatilelong Completedtasks;
Worker (Runnable firsttask) {
SetState (-1); You cannot interrupt before calling Runworker
This.firsttask = Firsttask;
This.thread = Getthreadfactory (). Newthread (this);
}
Public Voidrun () {
Runworker (this);
}
......
.......
Voidinterruptifstarted () {
Threadt;
if (getState () >= 0 && (t = thread)! = null &&!t.isinterrupted ()) {
try{
T.interrupt ();
}catch (SecurityException ignore) {
}
}
}
}
It is visible that the worker has both wrapped the Runnable object--task and wrapped a thread object--as an initialization parameter. Because the worker is also a Runnable object.
It then provides external execution and stop interfaces, run () and interruptifstarted (). Recall that the sample using thread above could not help but have a new understanding, we put a thread object to threadpoolexecutor after execution. The actual call is to the thread (Filetask ()) object, which we temporarily call Workerwrapper.
So our filetask.interrupt () operation outside the pool affects the Filetask object. Rather than workerwrapper. So it may not be particularly appropriate to call the start () method two times above. It should be more appropriate to run out of the Filetask.interrupt (), since the start () method has never been performed on the Filetask object. There will be errors when you go to interrupt. In detail for example with:
In this analysis, we have learned that there is no other way to manipulate these workers except for the Interruptworkers () method called Threadpoolexecutor.
private void Interruptworkers () {
Finalreentrantlock mainlock = This.mainlock;
Mainlock.lock ();
try {
for (Worker w:workers)
W.interruptifstarted ();
} finally {
Mainlock.unlock ();
}
}
Java using the default thread pool trampled pits (ii)