Getting started with multithreading and Lambda expressions
-
What is a thread
Process: a process includes the memory space allocated by the operating system, including one or more threads. A thread cannot exist independently. It must be part of a process. A process runs all the time until all sub daemon threads are finished. Multithreading can satisfy programmers to write efficient programs to make full use of CPU.
-
The life cycle of a thread
Thread is a dynamic execution process, which has a process from generation to death.
-
New status:
After using the new keyword and Thread class or its subclasses to create a Thread object, the object will be in the new state. It remains in this state until the program starts () the Thread.
-
Ready status:
When the thread object calls the start() method, the thread enters the ready state. The thread in the ready state is in the ready queue and needs to be scheduled by the thread scheduler in the JVM.
-
Operation status:
If the ready thread obtains CPU resources, it can execute run(), and the thread becomes running. Threads in the running state are the most complex. They can program blocking state, ready state and death state.
-
Blocking status:
If a thread executes sleep, suspend and other methods and loses its occupied resources, the thread will enter the blocking state from the running state. After the sleep time has expired or the device resources have been obtained, you can re-enter the ready state. It can be divided into three types:
-
Wait blocking: the thread in the running state executes the wait() method to make the thread enter the stage blocking state.
-
Synchronization blocking: the thread failed to acquire the synchronized synchronization lock (because the synchronization lock is occupied by other threads).
-
Other blocking: when an I/O request is issued by calling the thread's sleep () or join (), the thread will enter the blocking state. When the sleep() state times out, the join() waits for the thread to terminate or time out, the I/O processing is completed, and the thread returns to the ready state.
-
-
Death status:
When a running thread completes a task or other termination conditions occur, the thread will switch to the termination state.
thread priority
Each Java thread has a priority, which helps the operating system determine the scheduling order of threads.
The priority of a Java thread is an integer with a value range of 1 (Thread.MIN_PRIORITY) - 10(Thread.MAM_PRIORITY). By default, each thread is assigned a priority thread NORM_PRIORITY(5).
Threads with higher priority are more important to the program, and processor resources should be allocated before those with lower priority. However, thread priority can not guarantee the order of thread execution, and it is very platform dependent.
-
-
Create a thread
-
By inheriting the Thread class itself
-
By implementing the Runable interface
-
Create threads by implementing Callable and Future
-
① : inherit the java.lang.Thread class and override the run() method
The first way to create a Thread is to create a new class that inherits the Thread class, and then create an instance of the class.
The inherited class must override the run() method, which is the entry point for the new class. He must call the start() method to execute.
Although this method is listed as a multi-threaded implementation, it is essentially an instance of the Runnable interface.
package com.kkb.spring.hello.helleThread.test; //Thread creation method: inherit the thread class, override the run() method, and call start to start the thread //Summary: thread startup is not necessarily executed immediately, but is scheduled by the CPU public class TestThread extends Thread{ @Override public void run() { for (int i = 0; i < 20; i++) { System.out.println("I'm looking at the code"+i); } } public static void main(String[] args) { //Create a thread object TestThread testThread=new TestThread(); //Call the start() method testThread.start(); for (int i = 0; i < 20; i++) { System.out.println("I'm learning multithreading"+i); } } }
② : implement the Runable interface, override the run() method, and then wrap it with the Thread class
package com.kkb.spring.hello.helleThread.test; //Create a thread by implementing the runnable interface public class TestThread3 implements Runnable{ public static void main(String[] args) { TestThread3 testThread3=new TestThread3(); new Thread(testThread3).start(); for (int i = 0; i < 20; i++) { System.out.println("I'm looking at the code"+i); } } @Override public void run() { for (int i = 0; i < 20; i++) { System.out.println("I'm learning multithreading"+i); } } }
These two methods focus on Thread and Runable, inherit Thread class, write run() method into class, implement Runable interface, write run() method into interface, and then wrap it with Thread class. Both methods call start() method of Thread class to start Thread.
There is no obvious difference between the two in essence, but there are great differences in appearance. The first method is to inherit the Thread class. Because java is single inheritance, if you inherit the Thread class, you can't inherit other classes. It's a little restricted and inflexible in inheritance. The second method is to solve the inflexible problem of the first single inheritance. So the second method is usually used.
Other variants:
public static void main(String[] args) { //new MyThread().start(); //new Thread(new MyRunable()).start(); //Anonymous Inner Class new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"\t"+Thread.currentThread().getId()); } }).start //The tail code block is a syntax sugar in the form of an internal anonymous class new Thread(){ @Override public void run() { System.out.println(Thread.currentThread().getName()+"\t"+Thread.currentThread().getId()); } }.start(); //Runnable is a functional interface, so you can use Lamda expressions Runnable runnable=()->{ System.out.println(Thread.currentThread().getName()+"\t"+Thread.currentThread().getId()); }; new Thread(runnable).start(); }
③ : implement the Callable interface, rewrite the call() method, and then package it as java.util.concurrent.FutureTask, and then package it as Thread callable: for threads with return value, you can cancel the thread and judge whether the thread has completed execution.
package com.kkb.spring.hello.helleThread.test; import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.concurrent.*; //Thread creation method 3: implement the callable interface public class TestCallable implements Callable { private String url;//Picture address private String name;//File name public TestCallable(String url, String name) { this.url = url; this.name = name; } @Override public Boolean call() throws Exception { WebDownloader1 webDownloader=new WebDownloader1(); webDownloader.doenloader(url,name); System.out.println("Downloaded a file named:"+name); return true; } public static void main(String[] args) { TestCallable t1=new TestCallable("https://img.kaikeba.com/736161901202lzci.png?imageMogr2/quality/85/format/webp","1.JPG"); TestCallable t2=new TestCallable("https://img.kaikeba.com/411121111202oauc.jpg?imageMogr2/quality/85/format/webp","2.JPG"); TestCallable t3=new TestCallable("https://img.kaikeba.com/742160111202ryal.jpg?imageMogr2/quality/85/format/webp","3.JPG"); //Create execution service ExecutorService service= Executors.newFixedThreadPool(3); //Execute commit Future<Boolean> s2 = service.submit(t1); Future<Boolean> s1 = service.submit(t2); Future<Boolean> s3 = service.submit(t3); //Get results try { Boolean r2 = s2.get(); Boolean r3 = s1.get(); Boolean r1 = s3.get(); System.out.println(r1); System.out.println(r2); System.out.println(r3); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } //Shut down service service.shutdown(); } } class WebDownloader1{ public void doenloader(String url,String name){ try { FileUtils.copyURLToFile(new URL(url),new File(name)); } catch (IOException e) { e.printStackTrace(); System.out.println("IO abnormal,doenloader There is a problem with the method"); } } }
Static proxy
You: real role
Wedding company: represent you and help you deal with your marriage
Marriage: both roles implement the marriage interface
package com.kkb.spring.hello.helleThread.test; //Static proxy mode //It's true that both object and proxy object should implement the same interface //The proxy object is really a role to proxy //Proxy objects can do many things that real objects can't do //Really focused on doing their own things public class StaticProxy { public static void main(String[] args) { You you=new You();//Are you getting married new Thread(()-> System.out.println("i love you")).getName(); new WeddingCompany(new You()).happyMarry(); WeddingCompany weddingCompany=new WeddingCompany(new You()); weddingCompany.happyMarry(); } } //Marriage interface interface Marry{ void happyMarry(); } //Real role class You implements Marry{ @Override public void happyMarry() { System.out.println("Xiao Ming is getting married. He's so happy"); } } //Acting role to help Xiao Ming get married class WeddingCompany implements Marry{ //Delegate who -- > real target role private Marry target; public WeddingCompany(Marry target) { this.target = target; } @Override public void happyMarry() { befor(); this.target.happyMarry();//This is a real object after(); } private void after() { System.out.println("Final payment after marriage"); } private void befor() { System.out.println("Before marriage, decorate the wedding scene"); } }
Lamda expression
Lambda expression is a new feature of JDK8. It can replace most anonymous internal classes and write more elegant Java code. Especially in collection traversal and other collection operations, it can greatly optimize the code structure.
-
λ The first letter in the Greek alphabet is Lambda in English
-
Avoid too many anonymous inner class definitions
-
Its essence belongs to the concept of functional programming
Why use lambda expressions
-
Avoid too many anonymous inner class definitions
-
It can make your code look concise
-
A pile of meaningless code is removed, leaving only the core logic
Functional interface
Any interface that contains only one abstract method is a functional interface.
@FunctionalInterface public interface Runnable { public abstract void run(); }
For functional interfaces, we can create interface objects through lambda expressions.
package com.kkb.spring.hello.helleThread.lamda; /** * Push to lambda expression */ public class TestLambda { //3. Static inner class static class Like2 implements ILike{ @Override public void lambda() { System.out.println("i like lambda2"); } } public static void main(String[] args) { ILike like=new Like(); like.lambda(); Like2 like2 = new Like2(); like2.lambda(); //4. Local inner class class Like3 implements ILike{ @Override public void lambda() { System.out.println("i like lambda3"); } } Like3 like3 = new Like3(); like3.lambda(); //5. Anonymous inner class like=new ILike(){ @Override public void lambda() { System.out.println("i like lambda4"); } }; like.lambda(); //6. Simplify with lambad like=()->{ System.out.println("i like lambda5"); }; like.lambda(); } } //1. Define a functional interface interface ILike{ void lambda(); } //2. Implementation interface class Like implements ILike{ @Override public void lambda() { System.out.println("i like lambda"); } }