3. Basic operation of java process
3.1. Create process
Method 1: directly use Thread
// The parameter of the constructor is to assign a name to the thread. It is recommended to give a name to the thread (setName() is also acceptable) Thread t1 = new Thread("t1") { @Override // The task to be executed is implemented in the run method public void run() { log.debug("hello"); } }; t1.start();
Method 2: use Runnable to cooperate with Thread
Separate [thread] from [task] (code to be executed). Thread represents thread and Runnable runnable task (code to be executed by thread) test2 java
// Create task object Runnable task2 = new Runnable() { @Override public void run() { log.debug("hello"); } }; // Parameter 1 is the task object; Parameter 2 is the name of the thread. It is recommended to give the thread a name Thread t2 = new Thread(task2, "t2"); t2.start();
After 1.8, lambda expression is used to simplify the writing method
// Create task object Runnable task2 = () -> log.debug("hello"); // Parameter 1 is the task object; Parameter 2 is the thread name, which is recommended Thread t2 = neaw Thread(task2, "t2"); t2.start();
It can also be a little simpler
// Parameter 1 is the task object; Parameter 2 is the thread name, which is recommended Thread t2 = neaw Thread(() -> log.debug("hello"), "t2"); t2.start();
Shortcut key for simplifying lamba expression in idea: alt +enter
Summary
Method 1 combines threads and tasks. Method 2 separates threads and tasks. It is easier to use runnable to cooperate with high-level API s such as Thread pool. Runnable makes the task class separate from the Thread inheritance system and more flexible. By looking at the source code, we can find that method 2 is actually executed through method 1!
It should be noted that:
- If the run() method of Thread is run directly, it is called by the main Thread
Method 3: FutureTask with Thread
FutureTask can receive parameters of Callable type, which is used to deal with the situation that there are returned results java
public static void main(String[] args) throws ExecutionException, InterruptedException { // The third method of multithreading can return data or throw exceptions. The returned data needs to be received with get FutureTask futureTask = new FutureTask<>(new Callable<Integer>() { @Override public Integer call() throws Exception { log.debug("Multithreaded task"); Thread.sleep(100); return 100; } }); new Thread(futureTask,"My name").start(); log.debug("Main thread"); //{} indicates occupancy. The actual value is to buy your parameters and obtain the results. If necessary, you can get the execution result through the get method, which will block until the task returns the result. log.debug("{}",futureTask.get()); }
Future is to cancel and query the execution results of specific Runnable or Callable tasks.
public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
Future provides three functions:
- Judge whether the task is completed;
- Ability to interrupt tasks;
- Be able to obtain task execution results.
3.3 methods of viewing process threads
windows
The task manager can view the process and the number of threads, and can also be used to kill the process tasklist View process taskkill Kill process tasklist | findstr java View all java thread
linux
ps -fe View all processes ps -fT -p <PID> View a process( PID)All threads of kill Kill process top Press uppercase H Toggles whether threads are displayed top -H -p <PID> View a process( PID)All threads of ps -fe | grep java View all java process
Java
jps Command view all Java process jstack <PID> View a Java Process( PID)Status of all threads jconsole To see a Java Operation of threads in the process (graphical interface)
jconsole remote monitoring configuration
You need to run your java class as follows
java -Djava.rmi.server.hostname=`ip address` -Dcom.sun.management.jmxremote - Dcom.sun.management.jmxremote.port=`Connection port` -Dcom.sun.management.jmxremote.ssl=Secure connection - Dcom.sun.management.jmxremote.authenticate=Is it certified java class
Modify the / etc/hosts file to map 127.0.0.1 to the host name
If you want to authenticate access, you also need to do the following steps
Copy jmxremote Password file
Modify jmxremote Password and jmxremote The permission of access file is 600, that is, the file owner can read and write
Fill in controlRole (user name) and R & D (password) when connecting
example:
3.2 thread operation principle
3.2.1. Virtual machine stack and stack frame
Pseudo machine stack describes the memory model of Java method execution: when each method is executed, a stack frame will be created at the same time to store local variable table, operand stack, dynamic link, method exit and other information, which is private to the thread. When multithreading is used in Java, each thread will maintain its own stack frame! Each thread can only have one active stack frame, corresponding to the method currently executing
3.2.2. Thread Context Switch
For the following reasons, the cpu no longer executes the current thread, but executes the code of another thread
- The cpu time slice of the thread runs out (each thread executes in turn. See the previous concept of parallelism)
- garbage collection
- Threads with higher priority need to run
- The thread calls sleep, yield, wait, join, park, synchronized, lock and other methods
When a Context Switch occurs, the operating system needs to save the state of the current thread and restore the state of another thread. The corresponding concept in Java is the Program Counter Register, which is used to remember the execution address of the next jvm instruction and is private to the line
3.3 common methods of thread
3.3.1 start and run
Call start
public static void main(String[] args) { Thread thread = new Thread(){ @Override public void run(){ log.debug("I am a new thread running"); FileReader.read(fileName); } }; thread.setName("New thread"); thread.start(); log.debug("Main thread"); }
Output: the program runs on thread t1, and the call of contents in the run() method is asynchronous test4 java
11:59:40.711 [main] DEBUG com.concurrent.test.Test4 - Main thread 11:59:40.711 [New thread] DEBUG com.concurrent.test.Test4 - I am a new thread running 11:59:40.732 [New thread] DEBUG com.concurrent.test.FileReader - read [test] start ... 11:59:40.735 [New thread] DEBUG com.concurrent.test.FileReader - read [test] end ... cost: 3 ms
Call run
Put the thread of the above code start(); Change to thread run(); The output results are as follows: the program is still running in the main thread, and the call of the contents in the run () method is still synchronous
12:03:46.711 [main] DEBUG com.concurrent.test.Test4 - I am a new thread running 12:03:46.727 [main] DEBUG com.concurrent.test.FileReader - read [test] start ... 12:03:46.729 [main] DEBUG com.concurrent.test.FileReader - read [test] end ... cost: 2 ms 12:03:46.730 [main] DEBUG com.concurrent.test.Test4 - Main thread
Summary
Calling run() directly is to execute run() in the main thread. If no new thread is started, the main thread is used. Using start() is to start a new thread. The code in the run() method is executed indirectly through the new thread
3.3.2 sleep and yield
sleep
- Calling sleep will make the current thread enter the Timed Waiting state (blocking) from Running
- Other threads can use the interrupt method to interrupt the sleeping thread, and the interrupted thread will throw an InterruptedException exception [Note: the interrupted thread here is the sleeping thread, not the thread in other states]
- The thread after sleep may not be executed immediately (it needs to be allocated to cpu time slice)
- It is suggested to replace Thread's sleep() with TimeUnit's sleep() for better readability
Tip: sleep() of TimeUint
yield
- Calling yield will enable the current thread to enter the Runnable ready state from Running, and then schedule other threads.
- The specific implementation depends on the task scheduler of the operating system (that is, there may be no other thread executing. Although the yield method is called, it is useless)
3.3.3. thread priority
- The thread priority will prompt the scheduler to schedule the thread first, but it is only a hint. The scheduler can ignore it. If the cpu is busy, the thread with high priority will get more time slices, but when the cpu is idle, the priority has little effect
- Corresponding operation
thread1.setPriority(Thread.MAX_PRIORITY); //Set to highest priority
3.3.4. join method
- Call t1. in main thread Join, the main thread will wait for the T1 thread to execute before continuing
private static void test1() throws InterruptedException { log.debug("start"); Thread t1 = new Thread(() -> { log.debug("start"); sleep(1); log.debug("end"); r = 10; },"t1"); t1.start(); // t1.join(); // If you don't add t1 Join(), at this time, the main thread will not wait for t1 thread to assign a value to R, and the main thread will directly output r=0 // If you add t1 Join(), the main thread will wait until the t1 thread finishes executing (synchronous), r=10; log.debug("The result is:{}", r); log.debug("end"); }
The diagram is as follows:
Thinking: time to run while waiting for multiple results'
static int r1 = 0; static int r2 = 0; public static void main(String[] args) throws InterruptedException { test2(); } private static void test2() throws InterruptedException { //Thread t1 Thread t1 = new Thread(() -> { sleep(1); r1 = 10; }); //Thread t2 Thread t2 = new Thread(() -> { sleep(2); r2 = 20; }); long start = System.currentTimeMillis(); t1.start(); t2.start(); t1.join(); t2.join(); long end = System.currentTimeMillis(); log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start); }
Because the waiting time of thread t1 is 1ms and the waiting time of line t2 is 2ms, thread t2 will not end until 1ms after thread t1 runs. Run for 2ms in total and output.
As shown in the figure:
After exchange:
static int r1 = 0; static int r2 = 0; public static void main(String[] args) throws InterruptedException { test2(); } private static void test2() throws InterruptedException { //Thread t1 Thread t1 = new Thread(() -> { sleep(1); r1 = 10; }); //Thread t2 Thread t2 = new Thread(() -> { sleep(2); r2 = 20; }); long start = System.currentTimeMillis(); t1.start(); t2.start(); t2.join(); t1.join(); long end = System.currentTimeMillis(); log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start); }
After the thread t2join ends, it can output immediately. The total time is still two seconds.
Parameters in the join() function
At the same time, parameters can also be written in join(),
-
When the parameter is less than the actual running time, the main thread waits for the parameter time before starting action
static int r1 = 0; static int r2 = 0; public static void main(String[] args) throws InterruptedException { test3(); } public static void test3() throws InterruptedException { Thread t1 = new Thread(() -> { sleep(2); r1 = 10; }); long start = System.currentTimeMillis(); t1.start(); // join end, wait for end t1.join(1500); long end = System.currentTimeMillis(); log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start); }
-
When the parameter is greater than the actual running time, the main thread will run according to the actual running time.
static int r1 = 0; static int r2 = 0; public static void main(String[] args) throws InterruptedException { test3(); } public static void test3() throws InterruptedException { Thread t1 = new Thread(() -> { sleep(2); r1 = 10; }); long start = System.currentTimeMillis(); t1.start(); //End of operation, wait for end t1.join(3000); long end = System.currentTimeMillis(); log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start); }
3.3.5. interrupt
Interrupt is a unique interrupt method. It does not terminate the thread itself. It is often used together with the interrupt flag to make the thread termination more "elegant".
- When interrupt interrupts a running thread, the interrupt flag becomes true
- Interrupting a thread in sleep status will report the corresponding exception and will not change the interrupt flag to false
Interrupt the thread in sleep
private static void test1() throws InterruptedException { Thread t1 = new Thread(()->{ sleep(1); }, "t1"); t1.start(); sleep(0.5); t1.interrupt(); log.debug(" Interrupt state: {}", t1.isInterrupted()); }
output
java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at java.lang.Thread.sleep(Thread.java:340) at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386) at cn.itcast.n2.util.Sleeper.sleep(Sleeper.java:8) at cn.itcast.n4.TestInterrupt.lambda$test1$3(TestInterrupt.java:59) at java.lang.Thread.run(Thread.java:745) 21:18:10.374 [main] c.TestInterrupt - Interrupt state: false
Interrupt a running thread
private static void test2() throws InterruptedException { Thread t2 = new Thread(()->{ while(true) { Thread current = Thread.currentThread(); boolean interrupted = current.isInterrupted(); if(interrupted) { log.debug(" Interrupt state: {}", interrupted); break; } } }, "t2"); t2.start(); sleep(0.5); t2.interrupt(); }
20:57:37.964 [t2] c.TestInterrupt - Interrupt state: true
Note: the difference between isInterrupted and interrupted
The former changes the break flag to true without automatically changing it to false, while the latter automatically changes it to false
3.4. The two-stage termination mode of termination mode (I) is realized by interruption
The two-phase termination pattern comes from the use of heap break method and break mark
The general operation is as follows:
To put it simply: use a monitoring thread to monitor all threads. During the running process, always check whether the interrupt flag of the current thread is true. When the interrupt flag is true, stop the thread.
And we can stop the thread through this.
If the current thread is interrupted during normal operation, we can get the above results. If it is interrupted during sleep, we need to manually change the flag to true
The actual code is as follows:
public class Test7 { public static void main(String[] args) throws InterruptedException { Monitor monitor = new Monitor(); monitor.start(); Thread.sleep(3500); monitor.stop(); } } class Monitor { Thread monitor; /** * Start monitor thread */ public void start() { //Set the wire controller thread to monitor the thread status monitor = new Thread() { @Override public void run() { //Start non-stop monitoring while (true) { //Determine whether the current thread is interrupted if(Thread.currentThread().isInterrupted()) { System.out.println("Processing subsequent tasks"); //Terminate thread execution break; } System.out.println("Monitor running..."); try { //Thread sleep Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); //If you are interrupted during sleep, the interrupt flag will not be set to true. At this time, you need to reset the interrupt flag Thread.currentThread().interrupt(); } } } }; monitor.start(); } /** * Used to stop the monitor thread */ public void stop() { //Interrupt thread monitor.interrupt(); } }
3.5 interrupt park thread
Breaking the park thread is a method to stop the current thread on the park () line. It can be controlled by the interrupt flag. It takes effect when the interrupt flag is truepark() loses its function and false
private static void test3() throws InterruptedException { Thread t1 = new Thread(() -> { log.debug("park..."); LockSupport.park(); log.debug("unpark..."); log.debug("Interrupt status:{}", Thread.currentThread().isInterrupted()); }, "t1"); t1.start(); sleep(0.5); t1.interrupt(); }
If the interrupted thread is not restored manually, the interrupt flag will not be restored by itself, and the isInterrupted() method will not be restored automatically, so we can use thread Interrupted() clears the interrupted state.
3.6. Methods not recommended
3.7. Main thread and daemon thread
By default, Java processes need to wait for all threads to finish running before they end. There is a special thread called a daemon thread. As long as other non daemon threads finish running, even if the code of the daemon thread is not executed, it will be forced to end.
log.debug("Start running..."); Thread t1 = new Thread(() -> { log.debug("Start running..."); sleep(2); log.debug("End of operation..."); }, "daemon"); // Set this thread as a daemon thread t1.setDaemon(true); t1.start(); sleep(1); log.debug("End of operation...");
//result 08:26:38.123 [main] c.TestDaemon - Start running... 08:26:38.213 [daemon] c.TestDaemon - Start running... 08:26:39.215 [main] c.TestDaemon - End of operation...
be careful
Garbage collector thread is a kind of daemon thread
Acceptor and Poller threads in Tomcat are daemon threads, so Tomcat will not wait for them to finish processing the current request after receiving the shutdown command
3.8 five states
At the operating system level, we can divide the operation of threads into five states:
3.9. Six states
According to the division in thread state(), we can divide threads into six states
Test of six states:
@Slf4j(topic = "c.TestState") public class TestState { public static void main(String[] args) throws IOException { Thread t1 = new Thread("t1") { // new status @Override public void run() { log.debug("running..."); } }; Thread t2 = new Thread("t2") { @Override public void run() { while(true) { // runnable status } } }; t2.start(); Thread t3 = new Thread("t3") { @Override public void run() { log.debug("running..."); } }; t3.start(); Thread t4 = new Thread("t4") { @Override public void run() { synchronized (TestState.class) { try { Thread.sleep(1000000); // timed_waiting displays the blocking status } catch (InterruptedException e) { e.printStackTrace(); } } } }; t4.start(); Thread t5 = new Thread("t5") { @Override public void run() { try { t2.join(); // waiting status } catch (InterruptedException e) { e.printStackTrace(); } } }; t5.start(); Thread t6 = new Thread("t6") { @Override public void run() { synchronized (TestState.class) { // blocked status try { Thread.sleep(1000000); } catch (InterruptedException e) { e.printStackTrace(); } } } }; t6.start(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } log.debug("t1 state {}", t1.getState()); log.debug("t2 state {}", t2.getState()); log.debug("t3 state {}", t3.getState()); log.debug("t4 state {}", t4.getState()); log.debug("t5 state {}", t5.getState()); log.debug("t6 state {}", t6.getState()); } }