Java beginner's notes in Silicon Valley - multithreading
Multithreading understanding
Understanding: compare a program to a high-speed toll station, then a toll window is a thread, and multiple windows are multi threads.
Key points:
- Each thread has a separate stack and a program counter (pc).
- Multiple threads share a heap
- Each thread is performed independently
Creation and use of threads
- Create Thread 1 (not recommended): write a subclass to inherit Thread and override the run() method
public class MyThread extends Thread{ @Override public void run() {//Override the run() method for (int i = 0; i < 5; i++) System.out.println(Thread.currentThread().getName() + ":" + i); } }
- Using thread 1: call the start() method
public class Test { public static void main(String[] args) { MyThread t1 = new MyThread(); MyThread t2 = new MyThread();//A second thread is created here t1.start(); t2.start(); } }
Operation results:
- Create thread 2 (recommended): write a class that implements the Runable interface, override the run() method, and construct a thread object with the object of this class as a parameter. Thread objects with the same parameters share the same heap area.
class MyThread implements Runnable{ int i = 10; @Override public void run() {//Override the run() method while(i > 0) { System.out.println(Thread.currentThread().getName() + ":" + i--); } } } public class Test { public static void main(String[] args) { MyThread m = new MyThread(); Thread t1 = new Thread(m); t1.start(); } }
- You can also directly create and execute a thread in the form of an anonymous class:
new Thread(){ @Override public void run() { //sentence } }.start();
Common methods in Thread class
Method name | effect |
---|---|
getName() | Returns the name of the current thread |
setName() | Sets the name of the current thread |
currentThread() | Returns the current thread (static method) |
yeild() | After calling a.yeild in a thread, CPU chooses another thread to execute. |
join() | After calling b.join in a thread, a blocks, and B executes to a after execution. |
sleep(x) | Current thread blocking x milliseconds (static method) |
isAlive() | Returns whether the current thread is alive |
thread priority
- Threads have priority. When CPU switches threads, it is more likely to switch to threads with high priority.
- Priority is int type 1 < = value of priority < = 10
- Thread defines three (static int) values
identifier | value |
---|---|
MAX_PRIORITY | 10 |
NORM_PRIORITY | 5 |
MIN_PRIORITY | 1 |
- Priority related methods
method | effect |
---|---|
getPriority() | Returns the priority of the thread |
setPriority(x) | Set priority to x |
Thread life cycle
Thread safety problem solving
Multiple threads may cause thread safety problems when operating shared data. Solutions:
- 1. synchronized keyword solution
synchronized (obj) {//obj is a lock and can be any object //Code block for manipulating shared data }
Principle: multiple code blocks locked by the same lock can only be executed after one is executed
The method of Runnable implements multithreading, and the general lock is this
The method of inheriting Thread implements multithreaded lock, which is generally the subclass name class
-
- Using the method with synchronized keyword (not recommended), the method declared as synchronized is equivalent to adding the default lock - class name to the whole function class
public synchronized void method(){ }
-
- JDK5. Lock interface resolution after 0
public class MyThread implements Runnable{ int i = 30; //JDK5. Sync lock interface from 0 (lock) static ReentrantLock lock = new ReentrantLock();//ReentrantLock is the Lock interface implementation class @Override public void run() { while(true) { lock.lock(); if (i > 0)//Manual locking System.out.println(i--); else break; lock.unlock();//Manual unlocking } } } public class Test { public static void main(String[] args) { MyThread m = new MyThread(); new Thread(m).start(); new Thread(m).start(); } }
Deadlock problem
public static void main(String[] args) { Object a = new Object(); Object b = new Object(); new Thread(){//Thread one @Override public void run() { synchronized(a){ System.out.println("a-"); try { sleep(1000);//sleep increases deadlock probability }catch (Exception e){ e.printStackTrace(); } synchronized(b){ System.out.println("a-b"); } } } }.start(); new Thread(){//Thread two @Override public void run() { synchronized(b){ System.out.println("b-"); try { sleep(1000); }catch (Exception e){ e.printStackTrace(); } synchronized(a){ System.out.println("b-a"); } } } }.start(); }
Thread 1: a lock nested b lock,
Thread 2: b lock nested a lock
If thread 1 executes lock B while thread 2 executes lock a, then the b lock of thread 1 cannot be executed (occupied by thread 2). Similarly, the a lock in thread 2 cannot be executed. Cause two threads to block, which is the deadlock problem
The output is as follows:
Thread communication
Methods related to thread communication (member methods of Object class)
method | effect |
---|---|
wait() | Block the current thread and unlock the lock in the thread |
notify() | Recover another blocked thread containing the current lock (based on thread priority) |
notifyAll() | Recover all blocked threads that contain the current lock |
All methods can only be invoked in the synchronous code block and the caller is a lock.
JDK5. How threads are created after 0
- Implement the Callable interface, override the call() method in the implementation class, and call() has a return value
See code for specific use:
public class MyThread implements Callable { @Override public Object call() throws Exception { System.out.println("Thread executing...."); return Integer.valueOf("20"); } } public class Test { public static void main(String[] args) throws ExecutionException, InterruptedException { MyThread m = new MyThread(); FutureTask f = new FutureTask(m);//Return value storage class Thread t = new Thread(f); t.start(); //Get return value Object i = f.get(); System.out.println("Return value:" + i); }
This approach enables generic programming
- Thread pool
The common method in the actual development process is to create multiple threads in advance and reallocate threads when there are tasks Avoid creating and destroying threads many times, save time and facilitate thread management.
public class Test { public static void main(String[] args) throws ExecutionException, InterruptedException { //ExecutorService is the interface of thread pool //Executors is a tool class. You can create a new thread pool ExecutorService s = Executors.newFixedThreadPool(10);//Thread pool of 10 threads Object o = s.submit(new Callable(){//The submit method is applicable to callable @Override public Object call() throws Exception { System.out.println("callable In execution"); return null; } }).get(); s.execute(new Runnable() {//execute applies to Runnable @Override public void run() { System.out.println("Runable In execution"); } }); s.shutdown();//Terminate thread pool }
Set thread pool properties to facilitate management
public class Test { public static void main(String[] args) throws ExecutionException, InterruptedException { ThreadPoolExecutor tp =(ThreadPoolExecutor) Executors.newFixedThreadPool(10); tp.setCorePoolSize(20);//Thread pool property settings tp.setMaximumPoolSize(100); } }