Multithreading
Four ways to create multithreading:
1.1 Inheritance of Thread Class
- Advantages: Simple code
- Disadvantage: Can't inherit other classes (Java single inheritance multiple implementations)
//Inheriting the Thread class public class ThreadDemo { public static void main(String[] args) { MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); MyThread t3 = new MyThread(); t1.setName("Thread 1:"); t2.setName("Thread 2:"); t1.start(); t2.start(); } } class MyThread extends Thread{ int i=100; @Override public void run() { while (i>0){ System.out.println(Thread.currentThread().getName()+i--); } } }
1.2 Implementation of runnable Interface
- Advantages: Other classes can be inherited, and instances that implement the interface can share resources (member variables)
- Disadvantage: Complex code
public class RunnableDemo { public static void main(String[] args) { RunableThread runableThread = new RunableThread(); Thread thread1 = new Thread(runableThread,"Thread 1:"); Thread thread2 = new Thread(runableThread,"Thread 2:"); thread1.start(); thread2.start(); } } class RunableThread implements Runnable{ int i; @Override public void run() { for (int i = 0; i <100 ; i++) { System.out.println(Thread.currentThread().getName()+i); } } }
1.3 Implement callable interface (wrapped by FuturTask class)
- Advantages: The call() method that implements the interface inside has a return value.
- Call the return value: By calling the get() method of FuturTask.
public class CallableDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { CallableThread callableThread = new CallableThread(); FutureTask futureTask1 = new FutureTask(callableThread); FutureTask futureTask2 = new FutureTask(callableThread); Thread t1 = new Thread(futureTask1,"Thread 1"); Thread t2 = new Thread(futureTask2,"Thread 2"); t1.start(); t2.start(); System.out.println(futureTask1.get()); System.out.println(futureTask2.get()); } } class CallableThread implements Callable{ int i=100; @Override public Object call() throws Exception { while (i>0){ System.out.println(Thread.currentThread().getName()+i--); } return Thread.currentThread().getName()+"Return value of thread,Print at the end of execution"; } }
1.4 Use Thread Pool
(The Executors class provides a series of factory methods to create thread pools, and the returned methods all implement the ExecutorService interface)
- Advantages: Automated assembly, easy management and recycling of resources
- Disadvantage: The Alibaba java development manual explicitly prohibits the use of Executors to create thread pools
- Reason: Executors creates thread pools without the length of the incoming blocking queue. A blocking queue is a boundless queue. For a boundless queue, tasks can be added to it indefinitely. In this case, too many tasks may cause memory overflow.
- Recommendation 1: Customize the ThreadPoolExecutor class to create threads, but cannot define thread names
- It is strongly recommended to use Guava's ThreadFactoryBuilder to create thread pools that can set thread names.
//The method of creating thread pool in JDK is easy to OOM. Not recommended public class ThreadPoolDemo { public static void main(String[] args) { //Create a specified number of thread pool objects ExecutorService pool = Executors.newFixedThreadPool(2); pool.submit(new RunableThread2()); pool.submit(new RunableThread2()); //Close thread pool pool.shutdown(); } } class RunableThread2 implements Runnable{ int i=100; @Override public void run() { for (int i = 0; i <10 ; i++) { System.out.println(Thread.currentThread().getName()+i); } } } //Why not create a thread pool with Executors and block the queue with the default size of Integer.Max_Value? public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } //Customize ThreadPool Executor and set the blocking queue size to 5 ExecutorService pool = new ThreadPoolExecutor(5, 10, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5)) //Ali recommends using Guava's ThreadFactoryBuilder class to create //Setting Thread Name ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("thread%d:").build(); //Create thread pools ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(5, 10, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10), threadFactory, new ThreadPoolExecutor.AbortPolicy());
2 Lock Interface's Advantage over synchronized Code Block
-
The acquisition and release locks can be displayed, and the use of locks is more flexible.
- Method in Lock:
- lock(); lock
- unlock(); unlock
- Method in Lock:
-
Fair lock can be easily realized
- Fair Lock: First come first served, first come first served; (Efficiency is not as high as unfair lock)
- Unfair Lock: A preemptive mechanism for acquiring locks, which may not necessarily get locks in the first place, and may not be accessible by threads at all.
-
Lock is an extended version of synchronized. Lock provides unconditional, round-robin (tryLock method), timing (tryLock method with parameters), interruptible (lock Interruptibly), and multi-conditional queue (new Conditions method) lock operations. The implementation classes of Lock basically support fair locks and unfair locks (default), while synchronized only supports unfair locks.