A thread is the basic unit of operation in the operating system. It is encapsulated in a process. A process can contain multiple threads. Even if we do not manually create a thread, the process will have a default thread running.
For JVM, when we write a single-threaded program to run, there are at least two threads in the JVM, one is the program we created and the other is garbage collection.
Basic thread Information
We can use the Thread. currentThread () method to obtain some information about the current Thread and modify it.
Let's look at the following code:
Copy codeThe Code is as follows: view and modify the attributes of the current thread
String name = Thread. currentThread (). getName ();
Int priority = Thread. currentThread (). getPriority ();
String groupName = Thread. currentThread (). getThreadGroup (). getName ();
Boolean isDaemon = Thread. currentThread (). isDaemon ();
System. out. println ("Thread Name:" + name );
System. out. println ("Priority:" + priority );
System. out. println ("Group Name:" + groupName );
System. out. println ("IsDaemon:" + isDaemon );
Thread. currentThread (). setName ("Test ");
Thread. currentThread (). setPriority (Thread. MAX_PRIORITY );
Name = Thread. currentThread (). getName ();
Priority = Thread. currentThread (). getPriority ();
GroupName = Thread. currentThread (). getThreadGroup (). getName ();
IsDaemon = Thread. currentThread (). isDaemon ();
System. out. println ("Thread Name:" + name );
System. out. println ("Priority:" + priority );
The listed attributes are described as follows:
GroupNameBy default, each thread is in a thread group. You can also create a thread group explicitly. A thread group can also contain sub-thread groups. In this way, threads and thread groups are created, it constitutes a tree structure.
Name, Each Thread has a name. If it is not explicitly specified, the name rule is "Thread-xxx ".
PriorityEach thread has its own priority. The JVM processes the priority in a "preemptible" manner. When the JVM discovers a thread with a higher priority, it immediately runs the thread. For Multiple Threads with the same priority, the JVM Round Robin the thread. The Java Thread priority ranges from 1 to 10. The default value is 5. The Thread class defines two constants: MIN_PRIORITY and MAX_PRIORITY to indicate the highest and lowest priority.
The following code defines two threads with different priorities:
Copy codeSample Code: thread priority
Public static void priorityTest ()
{
Thread thread1 = new Thread ("low ")
{
Public void run ()
{
For (int I = 0; I <5; I ++)
{
System. out. println ("Thread 1 is running .");
}
}
};
Thread thread2 = new Thread ("high ")
{
Public void run ()
{
For (int I = 0; I <5; I ++)
{
System. out. println ("Thread 2 is running .");
}
}
};
Thread1.setPriority (Thread. MIN_PRIORITY );
Thread2.setPriority (Thread. MAX_PRIORITY );
Thread1.start ();
Thread2.start ();
}
It can be seen from the running results that the low-priority thread runs only after the high-priority thread is completed.
IsDaemonThis attribute is used to control the relationship between parent and child threads. If it is set to true, when the parent thread ends, all its sub-threads also end. Otherwise, the sub-thread's life cycle is not affected by the parent thread.
Let's take a look at the following example:Copy codeThe Code is as follows: IsDaemon example
Public static void daemonTest ()
{
Thread thread1 = new Thread ("daemon ")
{
Public void run ()
{
Thread subThread = new Thread ("sub ")
{
Public void run ()
{
For (int I = 0; I <100; I ++)
{
System. out. println ("Sub Thread Running" + I );
}
}
};
SubThread. setDaemon (true );
SubThread. start ();
System. out. println ("Main Thread end .");
}
};
Thread1.start ();
}
The running result of the above Code, in and delete subThread. setDaemon (true); After comparison, we can find that the subthread in the latter running process will finish execution and then end, while in the former, the subthread will soon end.
How to Create a thread
The content above demonstrates some information in the default thread. How should I create a thread? In Java, we have three methods to create threads.
In Java, threads either inherit the Thread class or implement the Runnable interface.
Use internal classes to create threads
We can use internal classes to create threads. The process is to declare a Thread type variable and override the run method. The sample code is as follows:
Copy codeThe Code is as follows: use an internal class to create a thread
Public static void createThreadByNestClass ()
{
Thread thread = new Thread ()
{
Public void run ()
{
For (int I = 0; I <5; I ++)
{
System. out. println ("Thread" + Thread. currentThread (). getName () + "is running .");
}
System. out. println ("Thread" + Thread. currentThread (). getName () + "is finished .");
}
};
Thread. start ();
}
Inherit Thread to create Thread
We can derive a class from Thread and rewrite its run method. This method is similar to the above. The sample code is as follows:
Copy codeThe Code is as follows: derives the Thread class to create a Thread
Class MyThread extends Thread
{
Public void run ()
{
For (int I = 0; I <5; I ++)
{
System. out. println ("Thread" + Thread. currentThread (). getName () + "is running .");
}
System. out. println ("Thread" + Thread. currentThread (). getName () + "is finished .");
}
}
Public static void createThreadBySubClass ()
{
MyThread thread = new MyThread ();
Thread. start ();
}
Implement the Runnable interface to create a thread
We can define a class to implement the Runnable interface, and then use the instance of this class as the parameter for constructing the Thread variable constructor. The sample code is as follows:
Copy codeThe Code is as follows: implement the Runnable interface to create a thread
Class MyRunnable implements Runnable
{
Public void run ()
{
For (int I = 0; I <5; I ++)
{
System. out. println ("Thread" + Thread. currentThread (). getName () + "is running .");
}
System. out. println ("Thread" + Thread. currentThread (). getName () + "is finished .");
}
}
Public static void createThreadByRunnable ()
{
MyRunnable runnable = new MyRunnable ();
Thread thread = new Thread (runnable );
Thread. start ();
}
The preceding three methods can be used to create threads. In the sample code, the functions of thread execution are the same. What are the differences between the three methods?
This involves the multi-thread running mode in Java. For Java, the difference between multi-thread and single-object is as follows:
Multi-object and multi-threadThe program creates multiple thread objects during the running process, and each object runs one thread.
Multi-thread single objectThe program creates a thread object during running and runs multiple threads on it.
Obviously, from the perspective of thread synchronization and scheduling, multi-object and multi-thread needs to be simpler. The first two methods of thread creation are "multi-object and multi-thread". The third method can be "multi-object and multi-thread" or "single-object and single-thread ".
Let's take a look at the following sample code, which uses the Object. y method. This method will wake up a thread on the Object, and the Object. yyall method will wake up all threads on the Object.
Copy codeThe Code is as follows: notify example
Public class policysample {
Public static void main (String [] args) throws InterruptedException
{
Policytest ();
NotifyTest2 ();
NotifyTest3 ();
}
Private static void policytest () throws InterruptedException
{
MyThread [] arrThreads = new MyThread [3];
For (int I = 0; I <arrThreads. length; I ++)
{
ArrThreads [I] = new MyThread ();
ArrThreads [I]. id = I;
ArrThreads [I]. setDaemon (true );
ArrThreads [I]. start ();
}
Thread. sleep (500 );
For (int I = 0; I <arrThreads. length; I ++)
{
Synchronized (arrThreads [I])
{
ArrThreads [I]. Y ();
}
}
}
Private static void policytest2 () throws InterruptedException
{
MyRunner [] arrMyRunners = new MyRunner [3];
Thread [] arrThreads = new Thread [3];
For (int I = 0; I <arrThreads. length; I ++)
{
ArrMyRunners [I] = new MyRunner ();
ArrMyRunners [I]. id = I;
ArrThreads [I] = new Thread (arrMyRunners [I]);
ArrThreads [I]. setDaemon (true );
ArrThreads [I]. start ();
}
Thread. sleep (500 );
For (int I = 0; I <arrMyRunners. length; I ++)
{
Synchronized (arrMyRunners [I])
{
ArrMyRunners [I]. Policy ();
}
}
}
Private static void policytest3 () throws InterruptedException
{
MyRunner runner = new MyRunner ();
Thread [] arrThreads = new Thread [3];
For (int I = 0; I <arrThreads. length; I ++)
{
ArrThreads [I] = new Thread (runner );
ArrThreads [I]. setDaemon (true );
ArrThreads [I]. start ();
}
Thread. sleep (500 );
Synchronized (runner)
{
Runner. policyall ();
}
}
}
Class MyThread extends Thread
{
Public int id = 0;
Public void run ()
{
System. out. println ("the" + id + "thread is prepared to sleep for 5 minutes. ");
Try
{
Synchronized (this)
{
This. wait (5*60*1000 );
}
}
Catch (InterruptedException ex)
{
Ex. printStackTrace ();
}
System. out. println ("the" + id + "thread is awakened. ");
}
}
Class MyRunner implements Runnable
{
Public int id = 0;
Public void run ()
{
System. out. println ("the" + id + "thread is prepared to sleep for 5 minutes. ");
Try
{
Synchronized (this)
{
This. wait (5*60*1000 );
}
}
Catch (InterruptedException ex)
{
Ex. printStackTrace ();
}
System. out. println ("the" + id + "thread is awakened. ");
}
}
In the sample code, policytest () and policytest2 () are "multi-object and multi-Thread". Although the Thread in policytest2 () implements the Runnable interface, when it defines the Thread array, each element uses a new Runnable instance. Policytest3 () is a "single object multi-thread", because we only define a Runnable instance, and all threads will use this instance.
The yyall method is applicable to the scenario of "single object multithreading", because the notify method will only wake up a thread on the object at random.
Thread status Switching
For a thread, the state of the thread may be as follows:
Create: A Thread instance already exists, but the CPU also allocates resources and time slice for it.
Ready: the thread has obtained all the resources required for running, and only waits for the CPU to schedule the time.
Running: The thread is in the current CPU time, and the related logic is being executed.
Sleep: Generally the state after Thread. sleep is called. At this time, the Thread still holds various resources required for running, but will not be scheduled by the CPU.
Suspension: Generally the status after Thread. suspend is called. Similar to sleep, the CPU does not schedule the Thread. The difference is that in this status, the Thread releases all resources.
Death: The Thread stops running or the Thread. stop method is called.
Next we will demonstrate how to switch the thread status. First, we will use the following method:
Thread () or Thread (Runnable): constructs a Thread.
Thread. start: start the Thread.
Thread. sleep: switches the Thread to sleep state.
Thread. interrupt: interrupt Thread execution.
Thread. join: wait for the end of a Thread.
Thread. yield: gets the execution time slice of the Thread on the CPU and waits for the next scheduling.
Object. wait: Lock all threads on the Object until the notify method continues running.
Object. Y: Randomly wake up one thread on the Object.
Object. policyall: Wake up all threads on the Object.
The following is the Demo time !!!
Thread wait and wake up
Here we mainly use the Object. wait and Object. Policy methods. For more information, see the notify instance above. It should be noted that both wait and policy must target the same object. When we create a thread by implementing the Runnable interface, these two methods should be used on the Runnable object rather than the Thread object.
Sleep and wakeup of threads
Copy codeThe Code is as follows: Thread. sleep instance
Public class SleepSample {
Public static void main (String [] args) throws InterruptedException
{
SleepTest ();
}
Private static void sleepTest () throws InterruptedException
{
Thread thread = new Thread ()
{
Public void run ()
{
System. out. println ("Thread" + Thread. currentThread (). getName () + "will sleep for 5 minutes. ");
Try
{
Thread. sleep (5x60*1000 );
}
Catch (InterruptedException ex)
{
System. out. println ("Thread" + Thread. currentThread (). getName () + "Sleep is interrupted. ");
}
System. out. println ("Thread" + Thread. currentThread (). getName () + "sleep ends. ");
}
};
Thread. setDaemon (true );
Thread. start ();
Thread. sleep (500 );
Thread. interrupt ();
}
}
During the Thread sleep process, we can use Thread. interrupt to wake it up. At this time, the Thread will throw InterruptedException.
Thread termination
Although there is a Thread. stop method, this method is not recommended. We can use the sleep and wakeup mechanism above to let the Thread end the Thread when processing IterruptedException.
Copy codeThe Code is as follows: Thread. interrupt example
Public class StopThreadSample {
Public static void main (String [] args) throws InterruptedException
{
StopTest ();
}
Private static void stopTest () throws InterruptedException
{
Thread thread = new Thread ()
{
Public void run ()
{
System. out. println ("the thread is running. ");
Try
{
Thread. sleep (1*60*1000 );
}
Catch (InterruptedException ex)
{
System. out. println ("thread interrupted, end thread ");
Return;
}
System. out. println ("the thread ends normally. ");
}
};
Thread. start ();
Thread. sleep (500 );
Thread. interrupt ();
}
}
Thread Synchronization wait
When we create 10 sub-threads in the main Thread and expect all the 10 sub-threads to end, the main Thread will execute the following logic. At this moment, Thread. join will be launched.
Copy codeThe Code is as follows: Thread. join example
Public class JoinSample {
Public static void main (String [] args) throws InterruptedException
{
JoinTest ();
}
Private static void joinTest () throws InterruptedException
{
Thread thread = new Thread ()
{
Public void run ()
{
Try
{
For (int I = 0; I <5; I ++)
{
System. out. println ("the thread is running. ");
Thread. sleep (1000 );
}
}
Catch (InterruptedException ex)
{
Ex. printStackTrace ();
}
}
};
Thread. setDaemon (true );
Thread. start ();
Thread. sleep (1000 );
Thread. join ();
System. out. println ("the main thread ends normally. ");
}
}
We can try to annotate or delete thread. join (); and run the program again to find the difference.
Inter-thread Communication
We know that all threads in a process share the memory space. How can we transmit messages between different threads? When reviewing Java I/O, we talked about PipedStream and PipedReader. Here is where they play a role.
The following two examples have the same functions. The difference is that Stream and Reader/Writer are used respectively.
Copy codeThe Code is as follows: PipeInputStream/PipedOutpueStream example
Public static void communicationTest () throws IOException, InterruptedException
{
Final PipedOutputStream pos = new PipedOutputStream ();
Final PipedInputStream pis = new PipedInputStream (pos );
Thread thread1 = new Thread ()
{
Public void run ()
{
BufferedReader br = new BufferedReader (new InputStreamReader (System. in ));
Try
{
While (true)
{
String message = br. readLine ();
Pos. write (message. getBytes ());
If (message. equals ("end") break;
}
Br. close ();
Pos. close ();
}
Catch (Exception ex)
{
Ex. printStackTrace ();
}
}
};
Thread thread2 = new Thread ()
{
Public void run ()
{
Byte [] buffer = new byte [1024];
Int bytesRead = 0;
Try
{
While (bytesRead = pis. read (buffer, 0, buffer. length ))! =-1)
{
System. out. println (new String (buffer ));
If (new String (buffer). equals ("end") break;
Buffer = null;
Buffer = new byte [1024];
}
Pis. close ();
Buffer = null;
}
Catch (Exception ex)
{
Ex. printStackTrace ();
}
}
};
Thread1.setDaemon (true );
Thread2.setDaemon (true );
Thread1.start ();
Thread2.start ();
Thread1.join ();
Thread2.join ();
}
Copy codeThe Code is as follows: PipedReader/PipedWriter example
Private static void communicationTest2 () throws InterruptedException, IOException
{
Final PipedWriter pw = new PipedWriter ();
Final PipedReader pr = new PipedReader (pw );
Final BufferedWriter bw = new BufferedWriter (pw );
Final BufferedReader br = new BufferedReader (pr );
Thread thread1 = new Thread ()
{
Public void run ()
{
BufferedReader br = new BufferedReader (new InputStreamReader (System. in ));
Try
{
While (true)
{
String message = br. readLine ();
Bw. write (message );
Bw. newLine ();
Bw. flush ();
If (message. equals ("end") break;
}
Br. close ();
Pw. close ();
Bw. close ();
}
Catch (Exception ex)
{
Ex. printStackTrace ();
}
}
};
Thread thread2 = new Thread ()
{
Public void run ()
{
String line = null;
Try
{
While (line = br. readLine ())! = Null)
{
System. out. println (line );
If (line. equals ("end") break;
}
Br. close ();
Pr. close ();
}
Catch (Exception ex)
{
Ex. printStackTrace ();
}
}
};
Thread1.setDaemon (true );
Thread2.setDaemon (true );
Thread1.start ();
Thread2.start ();
Thread1.join ();
Thread2.join ();
}