Processes and Threads
- Processes are the basic unit by which a program requests resources from the operating system, such as memory space and file handles.
- Threads are the smallest unit of independently executable execution in a process.
JAVA Thread API
- Creating a thread in Java creates an instance of the Thread class.
- Each thread has its own task to perform. Thread task processing logic is implemented or invoked in the run method of the Thread class, so the run method is equivalent to the entry method for thread task logic processing, which is invoked by the java virtual machine when the corresponding thread is running, not by the application code.
- The start method of the Thread class is used to start related threads. The essence of starting a thread is to ask the java virtual machine to run the corresponding thread, and when the thread runs is determined by the thread scheduler. Therefore, although the start method is executed, this does not mean that the thread starts running. It may or may not run later.
Two constructors commonly used in Thread are Thread() and Thread(Runnable target), which create threads in the following ways:
Create threads by defining subclasses of the Thread class
public class WelcomeApp { public static void main(String[] args) { // Create Threads Thread welcomeThread = new WelcomeThread(); // Start Thread welcomeThread.start(); // Output Thread Name for Current Thread System.out.printf("1.Welcome! I'm %s.%n", Thread.currentThread().getName()); } } // Define subclasses of the Thread class class WelcomeThread extends Thread { // Implementing task processing logic for threads in this method @Override public void run() { System.out.printf("2.Welcome! I'm %s.%n", Thread.currentThread().getName()); } }
Create threads by implementing the Runnable interface
public class WelcomeApp1 { public static void main(String[] args) { // Create Threads Thread welcomeThread = new Thread(new WelcomeTask()); // Start Thread welcomeThread.start(); // Output Thread Name for Current Thread System.out.printf("1.Welcome! I'm %s.%n", Thread.currentThread().getName()); } } class WelcomeTask implements Runnable { // Implementing task processing logic for threads in this method @Override public void run() { // Output Thread Name for Current Thread System.out.printf("2.Welcome! I'm %s.%n", Thread.currentThread().getName()); } }
- Regardless of how you run it, once the thread's run method finishes executing, the corresponding thread finishes running, and the resources occupied by the running thread are garbage collected by the java virtual machine just like other java objects.
- An instance of Thread can only start once, and multiple calls to start() of an instance throw an IllegalThreadStateException exception.
You can use Thread.currentThread() gets the current thread, which in turn can set its properties or get information about it, such as:
Thread.currentThread().setName("thread A"); Thread.currentThread().getName();
In the above, the run method of a thread is usually called by a java virtual machine. However, a thread is also an instance of a Thread class, and the run method is also decorated by the public modifier. Therefore, the run method can also be called directly, but it is not usually done, which violates the original intention of our bedframe threads.
public class WelcomeApp { public static void main(String[] args) { // Create Threads Thread welcomeThread = new WelcomeThread(); // Start Thread welcomeThread.start(); // Output Thread Name for Current Thread System.out.printf("1.Welcome! I'm %s.%n", Thread.currentThread().getName()); welcomeThread.run(); } } // Define subclasses of the Thread class class WelcomeThread extends Thread { // Implementing task processing logic for threads in this method @Override public void run() { System.out.printf("2.Welcome! I'm %s.%n", Thread.currentThread().getName()); } } ==================Result================== 1.Welcome! I'm main. 2.Welcome! I'm Thread-0. 2.Welcome! I'm main.
Thread Properties
attribute Attribute type and purpose read-only Important considerations number
IDUsed to identify different threads with different numbers yes When a numbered thread has finished running, it may be used by subsequently created threads. Different threads have different numbers, but the uniqueness of the numbers is only valid for one run of the Java virtual machine. That is, after restarting a Java virtual machine, such as a Web server, some threads may be numbered the same as a thread that was last run by the Java virtual machine, so the value of this property is not appropriate for a unique identity, especially as a unique identity in the database, such as a primary key. Name
NameUsed to distinguish between different threads. The default value is related to the number of the thread in the format Thread-Thread-Thread Number, such as Thread-0 no Java does not prevent us from setting the name property of different threads to the same value. Nevertheless, setting the thread's name property can help with code debugging and problem location Thread Category
DaemonA value of true indicates that the corresponding thread is a daemon thread, otherwise the corresponding thread is a user thread. The default value of this property is the same as that of the parent thread of the corresponding thread. When a java program is stopped normally, the virtual machine will not stop immediately when a user thread has not finished executing and will wait for its execution to complete. However, if only the daemon thread has not finished executing, it will not prevent the virtual machine from stopping, which indicates that daemon threads are often used to perform tasks of lesser importance. For example, monitoring other threads no This property must be set before the corresponding thread starts, that is, the call to the setDaemon method must precede the call to the start method, or the setDaemon method will throw an IllegalThreadStateException exception. Threads responsible for some critical task processing are not suitable to be set as Daemons priority
PriorityThis property is essentially a hint to the thread scheduler to indicate which thread the application wants to run first. Java defines 10 priorities ranging from 1 to 10. The default value is generally 5. For a specific thread, the default priority value is equal to the priority value of its parent thread, the thread that created it no The default priority is usually sufficient. Setting this property value inappropriately can cause serious problems (thread hunger) Thread method
Method function Remarks static Thread
currentThread()Returns the current thread, the execution thread (object) of the current code Same code pair Thread. A call to currentThread(), whose return value may correspond to a different thread (object) void run() Task processing logic for implementing threads This method is called directly by a Java virtual machine and should not normally be called by an application void start() Start corresponding thread The return of this method does not mean that the corresponding thread has been started. The start method of a Thread instance can only be called once, and multiple calls can cause an exception to be thrown void join() Wait for the corresponding thread to finish running If Thread A calls the join method of Thread B, the execution of Thread A is suspended until the end of Thread B static void yield() Causes the current thread to voluntarily abandon its occupation of the processor, which may cause the current thread to be paused This method is unreliable. The current thread may continue to run when the method is called (depending on the current state of the system) static void sleep(long millis) Sleep (pause) the current thread for the specified time
Relationship between Thread and Runnable
Thread class implements Runnable interface
public class Thread implements Runnable{}
- Runnable is an interface and has only one method, so the class implementing Runnable has to re run the method.
The process of executing task logic in two ways
Implement the Runnable interface, override the run method
class WelcomeTask implements Runnable { @Override public void run() { //Task logic } }
new Thread(new WelcomeTask()).start();
The WelcomeTask instance is passed in Thread, which is eventually assigned to a target member variable in Thread
private Runnable target;
The specific process is as follows:
1. A parametric constructor that generates a ThreadName, for example, Thread-0public Thread(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0); }
2. Enter the first initialization function, there is no need to focus on other parameters, as there are other constructors that call init(...)
private void init(ThreadGroup g, Runnable target, String name,long stackSize){ init(g, target, name, stackSize, null, true); }
3. Layer 2 initialization function, i.e. target assignment
private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals) { if (name == null) { throw new NullPointerException("name cannot be null"); } this.name = name; ..... this.target = target; .... }
4. The Thread instance calls the start() method
public synchronized void start() { //ThreadStatus!= 0 means this Thread instance has already been started (), so it throws an exception if (threadStatus != 0) throw new IllegalThreadStateException(); ... try { //The local method start0() will eventually be called to start this thread start0(); ... } finally { ... } }
5. Local method starts the thread, handing it over to the virtual machine's thread scheduler
private native void start0();
6. Thread Scheduler Executes Thread Task Logic
//When a thread is started, the dispatcher helps us run the execution thread run() method, which is the task logic //If target!= When null calls the task logic implemented in WelcomeTask, otherwise nothing will be executed public void run() { if (target != null) { target.run(); } }
Inherit Thread class, override run method
class WelcomeThread extends Thread { @Override public void run() { //Task logic } }
new WelcomeThread().start(); ... //Task Scheduler directly calls the task logic implemented in WelcomeThread
The difference between the two ways
- Object-oriented angle: One is to implement extends Thread based on inheritance, the other is to combine new Thread(new Runable()) which is less coupled to inheritance.
Angle of object sharing: A CountingTask instance can be shared by multiple threads, so there may be competition for resources.
class CountingThread extends Thread { int count = 0; @Override public void run() { for (int i = 0; i < 100; i++) { i++; } } System.out.println("count:" + count); } class CountingTask implments Runnable { int count = 0; @Override public void run() { for (int i = 0; i < 100; i++) { i++; } } System.out.println("count:" + count); } public static void main(String[] args) { Thread thread; CountingTask task = new CountingTask(); for(int i = 0;i < 10;i++){ thread = new Thread(task); thread.start(); } for(int i = 0;i < 10;i++){ thread = new CountingThread(); thread.start(); } }
Thread life cycle
- New (New Creation)
Thread thread = new Thread();
At this point the thread is just ready for new and does not start execution. - Runnable
thread.start();
1.ready: No resources have been allocated yet.
2.running: Executing. block
1.Blocked does not acquire a lock for synchronized protected code.
2.Waiting1.Object.wait(); - o.notify()/o.notifyAll() 2.Thread.join(); - join Thread End/Interrupted Blocked and Waiting The difference is Blocked Waiting to release a resource, Waiting Is waiting for a condition to be reached.
Time Waiting sets some blockages for the time parameter.
1.Thread.sleep(m);- Time-out/join End of process/Interrupted.
2.Object.wait(m)
- Time out/o.notify()/o.notifyAll()
3.Thread.join(m)
- Time-out/join End of process/Interrupted.
- Terminated (Terminated)
1. The run method has finished executing normally.
2. An exception that was not caught occurred and terminated unexpectedly.