A soldier who doesn’t want to be a general is not a good soldier, and a Java programmer who doesn’t want to be an architect is not a good programmer! Why do you want to be an architect? Why do you want to work in a big factory?
At the Alma mater dance that year 18, I stood like a bandit and I swore with tears in my eyes that you had to see me
How does a Java program stop a thread?
It is recommended to use the exception method to terminate the thread. In a thread that you want to interrupt, call the interrupted() method. This method checks whether the current thread has been interrupted. This method does not cause the thread to stop immediately, but throws an exception if it returns true. Outside the thread, the interrupt() method is called to mark the thread as an interruption.
Let’s talk about multithreading in Java.
1. Four ways to implement multithreading in Java (four ways to create multithreading)?
Create Thread class by inheriting Thread class
- Subclass Thread and override the run method of the class. The body of the run method represents the task to be completed by the Thread. Therefore, the run() method is called the body of the execution.
- Creating an instance of the Thread subclass creates a Thread object.
- Call the start() method of the thread object to start the thread.
②. Create thread classes through the Runnable interface
- Define the implementation class of the Runnable interface and override the run() method of that interface, whose method body is also the thread execution body of that thread.
- Create an instance of the Runnable implementation class and use this instance as the target of a Thread to create a Thread object, which is the actual Thread object.
- Call the start() method of the thread object to start the thread.
③ Create threads with Callable and Future
- Create an implementation class for the Callable interface that implements the Call () method, which acts as the thread body and has a return value.
- Create an instance of the Callable implementation class that wraps the Callable object with a FutureTask class that wraps the return value of the Callable object’s call() method.
- Create and start a new Thread using the FutureTask object as the target of the Thread object.
- Call the Get () method of the FutureTask object to get the return value after the child thread completes execution.
You can create a thread by using the thread pool without new, thread reusable, use Executors to create a thread pool.
Extension 1: What is the difference between Runnable and Callable in Java?
- Callable defines a method called call(), while Runnable defines a method called run().
- Callable’s call method can have a return value, while Runnable’s run method cannot.
- The Call method of Callable can throw an exception, while the run method of Runnable cannot.
Extension 2: Can a class inherit Thread and implement the Runnable interface? <
You can. For example, the following program can be compiled. Because the Test class inherits the run() method from the Thread class, the run() method can be thought of as an implementation of the Runnable interface.
public class Test extends Thread implements Runnable { public static void main(String[] args) { Thread t = new Thread(new Test()); t.start(); }}Copy the code
2. Realize the synchronization of multiple threads.
In a multithreaded environment, often encounter data sharing problem, namely when multiple threads need to access the same resources, they need to be in a certain order to ensure that the resources can only be used by one thread at a time, otherwise, the application of the results will be unpredictable, in this case, it must be conducted for data synchronization.
In Java, there are four ways to implement synchronous mutually exclusive access: synchronized and Lock and wait()/notify()/notifyAll() and CAS.
① Synchronized.
A. Synchronize code blocks
Synchronized (object) {}Copy the code
The thread locks the object during execution. (Note that the object can be of any class, or you can use the this keyword or class object.)
Perhaps only a few lines of code in a method involve thread synchronization, so synchronized blocks control access to multiple threads more fine-grained than synchronized methods, Only the contents of a synchronized block cannot be accessed by multiple threads at the same time; other statements in a method can still be accessed by multiple threads at the same time (both before and after the synchronized block).
B. Modify non-static methods
When the synchronized keyword modifies a method, it is called a synchronized method.
Every object in Java has a lock, or monitor, When a thread accesses an object’s synchronized method, the object is locked, and no other thread can access the object’s synchronized method (meaning all synchronized methods, not just the same method) until the previous thread finishes executing the method (or Throw an exception) to release the lock of the object, and other threads can access the synchronized method of the object again.
Note that the object is locked. If the object is different, there is no restriction between the objects.
Note that if an object has multiple synchronized methods, and a thread has entered a synchronized method at some point, no other thread can access any synchronized methods of the object until the method has finished executing.
C. Modify static methods
When a synchronized method is modified static, as we saw earlier, a non-static synchronized method locks an object, but a static method does not belong to an object, but to a Class, and locks the Class object of the method. No matter how many objects a Class generates, they all correspond to the same Class object.
Therefore, when a thread accesses two static,synchronized methods on two objects of the same class, they are executed in sequential order, meaning that one thread executes the method first and the other thread starts only after the method is executed.
Conclusion:
- The synchronized method is a coarse-grained concurrency control that can only be executed by one line at a time.
- Synchronized blocks, on the other hand, are fine-grained concurrency control that only synchronizes code within a block, within a method; code outside the synchronized block can be accessed by multiple threads simultaneously.
②.
Using a Lock must be done ina try-catch-finally block, and the Lock release must be done ina finally block to ensure that the Lock is always released and to prevent deadlocks. When using Lock for synchronization, it is used in the following form:
Lock lock = ... ; lock.lock(); Try {// process tasks} catch(Exception ex){} finally{lock.unlock(); // release the lock}Copy the code
The difference between Lock and synchronized and the advantages of Lock You need to implement an efficient cache that allows multiple users to read, but only one user to write, in order to maintain its integrity. How would you implement that?
- Lock is an interface, while synchronized is a Java keyword and synchronized is a built-in language implementation.
- Synchronized will automatically release the lock occupied by the thread when an exception occurs, so it will not lead to the occurrence of lethal lock; UnLock (); unLock(); unLock(); unLock();
- Lock causes a thread waiting for a Lock to respond to an interrupt (interruptible Lock), whereas synchronized does not. With synchronized, the waiting thread waits forever and cannot respond to an interrupt (uninterruptible Lock).
- (tryLock() method: if the Lock was obtained, return true; Otherwise return false, which means the method will return immediately anyway. Don’t wait around until you get the lock. Synchronized can’t.
- Lock improves the efficiency of multiple threads performing read operations (read/write locks).
- Lock implements fair locking, while synchronized does not. In terms of performance, if threads are not competing fiercely for resources, the performance of the two is about the same, while when the resources are competing fiercely (that is, a large number of threads are competing simultaneously), the performance of Lock is much better than that of synchronized. So, in the specific use of appropriate circumstances to choose.
Extension 1: Difference between volatile and synchronized.
- Volatile is a variable modifier, while synchronized acts on code blocks or methods.
- Volatile does not lock variables and does not block threads. Synchronized locks variables and can cause threads to block.
- Volatile only enables change visibility of variables, and does not guarantee atomicity; Synchronized can be used to guarantee the visibility and primitivity of variable modification. Synchronized has two important implications: it ensures that only one thread can execute a protected portion of code at a time (mutex), and it ensures that changes made by one thread are visible to other threads (visibility of changes), flushing changes to variables into main memory before releasing the lock.
- Volatile variables are not optimized by the compiler, and instruction reordering is prohibited. Variables of the synchronized tag can be optimized by the compiler.
Extension 2: When can volatile replace synchronized? Volatile can be used instead of synchronized to ensure atomicity, consistency, and visibility when only shared resources are required.
Wait ()\notify()\notifyAll() .
In the history of Java, methods suspend() and resume() were used to suspend and wake up threads. However, many problems occurred, such as deadlock.
The solution can use object-targeted blocking, that is, thread blocking using the Wait () and notify() methods of the Object class.
First, the wait and notify methods are for objects, and calling wait() on any object will block the thread. Blocking also releases the lock on that object. Accordingly, calling notify() on any object randomly releases the blocked thread on that object, but it needs to acquire the lock again until it can proceed. Second, the wait and notify methods must be called from a synchronized block or method, and the lock object of the synchronized block or method must be the same as the lock object of the synchronized block or notify method, so that the current thread has successfully acquired the lock before the wait is called An object lock that is released by the current thread after a wait is executed.
Extension 1: Why are wait(),notify(), and notifyAll() defined in Object?
Because all three methods need to be defined in synchronized code blocks or methods whose calls depend on lock pairs, and the lock Object in synchronized code blocks or methods can be any Object, methods that can be called by any Object must be defined in the Object class.
Extension 2: What is the difference between notify() and notifyAll()?
Notify () and notifyAll() are methods that Object objects use to notify the threads waiting for the Object. Void notify(): Wakes up a thread waiting for this object and enters the ready queue waiting for CPU scheduling. Void notifyAll(): Wakes up all threads waiting for this object and enters the ready queue waiting for CPU scheduling. NotifyAll causes all threads waiting to be notified to exit the wait state. NotifyAll causes all threads waiting to be notified to exit the wait state. NotifyAll causes all threads waiting to be notified to exit the wait state. Notify A thread in wait state obtains the lock on the object, but does not alert other threads that are also waiting to be notified. When the first thread finishes running, the lock on the object is released, and the object is not notified again Statement, even if the object is idle, other threads waiting in wait wait until the object emits a notify or notifyAll. They wait to be notified or notifyAll instead of locking.
(4). The CAS
It is a non-blocking mode of synchronization. See the section above for details.
Extension 1: Classification of synchronous locks?
- Synchronized and Lock are pessimistic locks.
- Optimistic locking,CAS synchronization primitives, such as atomic classes, non-blocking synchronization modes.
Extension 2: Classification of locks?
- One is at the code level, such as synchronous lock, reentrant lock, fair lock, read/write lock in Java. Another is on the database level, the more typical is pessimistic lock and optimistic lock, table lock, row lock, page lock.
Extension 3: Pessimistic and Optimistic Locking in Java?
- Pessimistic lock: Pessimistic lock is the belief that there must be other threads competing for resources, so regardless of whether or not a contention will occur, pessimistic lock will always lock the resource first, causing all other threads that need to lock to hang, waiting for the thread that holds the lock to release the lock. Synchronized and Lock are pessimistic locks.
- Optimistic locking: Leave an operation unlocked each time, assuming no conflicts, and retry until it succeeds if it fails because of conflicts. When making a change or other operation it assumes that no other thread will do the same operation (race). This is an optimistic attitude, usually based on CAS atomic instructions. CAS usually does not suspend threads, so sometimes performance is better. An implementation of optimistic lock — CAS.
Implement communication between threads?
When threads can share resources, inter-thread communication is an important means of coordinating them.
1. Wait ()\notify()\notifyAll() in the Object class.
2. Use Condition interface.
- Condition is bound to Lock, and to create a Condition object of Lock, you must use the newCondition() method. Multiple Condition objects can be created in a Lock object, and threads can be registered in the specified Condition object, so that thread notification can be selective, and thread scheduling is more flexible.
- In Condition, we can replace wait() with await(), notify() with signal(), and notifyAll() with signalAll(). When calling a method in the Condition, it needs to be contained between lock() and unlock().
3. Pipes implement communication between threads.
- Implementation: One thread sends data to the output pipe stream, and another thread reads data from the input pipe stream.
- Basic process:
- 1) Create PipedOutputStream POS and PipedInputStream pis.
- 2) Match pos with PIS,pos.connect(pis).
- 3) The communication between threads can be realized by assigning POS to the thread of information input and Pis to the thread of information acquisition.
- Disadvantages:
- 1) A pipe flow can only pass data between two threads.
- The threads consumer1 and consumer2 read data from the pis at the same time. When the producer thread writes a piece of data (1,2,3,4,5,6) to the pipe stream, only one thread can fetch data at any given time, not both A pipe stream can only be used for communication between two threads because the producer sends data.
- 2) Pipe flows can only be sent one-way. If two threads are to communicate with each other, two pipe flows are needed.
- The producer thread pipes data to the consumer thread. If the consumer thread wants to send data to the producer thread, it needs to create another pipe flow, POS1, and PIS1, and assign POS1 to the Consumer1 thread and pis1 to the Consumer1 thread Assign producer1.
4. Use the volatile keyword as shown in the section above.
How to ensure thread safety?
If multiple threads run a piece of code simultaneously, it is thread-safe if the results of each run are the same as those of a single thread, and the values of other variables are the same as expected.
Synchronized,Lock, atomic classes (such as AtomicINTEGER, etc.), Synchronized containers, combined containers, blocking queues, Synchronized helper classes (such as CountDownLatch, Semaphore, CyclicBarrier).
The advantages and disadvantages of multithreading?
1. Advantages:
- Make full use of CPU and avoid CPU idling.
- The program responds faster.
2. Disadvantages:
-
The overhead of context switching
- When a CPU switches from executing one thread to executing another, it first stores local data, program Pointers, etc., from the previous thread, and then loads local data, program Pointers, etc., from another thread before executing. This switch is called a context switch. The CPU executes a thread in one context and then switches to a different context to execute another thread. Context switching is not cheap. If not necessary, context switches should be reduced.
-
Increased resource consumption
- Threads need some resources from the computer to run. In addition to the CPU, the thread needs some memory to maintain its local stack. It also takes some resources from the operating system to manage the line.
-
Programming is more complicated
- When multiple threads are accessing shared data, consider thread safety.
Write down three best practices for multithreading that you follow.
- Give the thread a meaningful name.
- Avoid locking and narrowing the scope of synchronization. I prefer synchronized blocks to synchronized methods, which give me absolute control over the lock.
- Use more synchronous helper classes and less wait and notify. First, synchronization AIDS such as CountDownLatch, Semaphore, and CyclicBarrier simplify coding, while wait and notify make it difficult to control complex control flows. Second, these classes are written and maintained by the best companies and will continue to be refined and refined in subsequent JDKS. With these higher-level synchronization tools, your programs can be optimized without much effort.
- Use concurrent containers more often than synchronous ones. The next time you need to use a Map, the first thing you should think about is using ConcurrentHashMap.
Is the performance of multithreading better than that of single thread?
B: Not necessarily. It depends on the specific task and the configuration of the computer. Such as:
- For a single-core CPU, if it is cpu-intensive tasks, such as decompressing files, the performance of multi-threading is worse than that of single-threading, because decompressing files requires CPU resources all the time. If multi-threading is used, the overhead caused by thread switching will degrade the performance. If it’s an interactive type of task, you definitely need to use multiple threads.
- For multi-core cpus, multi-threading is definitely better than single-threading for decompressing files, because multiple threads make better use of each core’s resources.
Types of locks in multithreading.
1. Reentrant lock
ReentrantLock and synchronized are both reentrant locks. If the current thread has acquired a lock held by a monitor object, that thread also holds the lock when it calls another synchronous method in that method. Such as:
public sychrnozied void test() {
xxxxxx;
test2();
}
public sychronized void test2() {
yyyyy;
}
Copy the code
In the above code snippet, executing the test method requires acquiring the object lock of the current object as the monitor, but test2’s synchronous method is called in the method.
If the lock is reentrant, the thread does not need to reacquire the lock on the current object when it calls test2 and can directly access the test2 method.
The greatest benefit of reentrant locks is to avoid deadlocks. If the lock is not reentrant, then the thread will wait for the lock to be released before calling test2. In fact, the lock is held by the current thread and cannot be acquired again, and the thread will produce a life or death lock when calling a synchronized method that contains the lock.
2. Interruptible lock
As the name suggests, a lock that responds to interrupts.
In Java,synchronized is not a breakable Lock, whereas Lock is a breakable Lock. The use of lockInterruptibly() already demonstrates the interruptibility of Lock. If thread A is executing the code in the lock, and thread B is waiting to acquire the lock, maybe because the waiting time is too long, thread B doesn’t want to wait, and wants to do other things first, we can tell it to interrupt itself or interrupt it in another line, this is called interruptible lock.
3. Fair lock
In Java,synchronized is an unfair lock that does not guarantee the order in which waiting threads acquire the lock. For ReentrantLock and ReentrantReadWriteLock, it is an unfair lock by default, but can be set to a fair lock.
Fair locking means that locks are acquired in the order in which they are requested. For example, if there are multiple threads waiting for a lock, when the lock is released, the thread that waited the longest (the thread that requested it first) will get the lock. This is a fair lock.
4. Read/write locks
Because of the read-write lock, the read operation between multiple threads does not conflict. ReadWriteLock is a read/write lock. It is an interface. ReentrantReadWriteLock implements this interface. Read locks can be obtained by readLock() and write locks by writeLock().
Ix. Lock optimization
1. The spin lock
- To make the thread wait, have the thread perform a busy loop (spin). The physical machine is required to have a superior processor. Spin wait avoids the overhead of thread switching, but it consumes processor time, so if the lock is held for a short period of time, spin wait works well, whereas spinning threads consume processor resources for nothing. The default number of spins is 10, which can be changed using the argument -xx :PreBlockSpin.
- Adaptive spin lock: The spin time is no longer fixed, but is determined by the previous spin time on the same lock and the state of the lock owner.
2. Remove lock
- The virtual machine just-in-time compiler, at runtime, removes locks that require synchronization on code but detect that there is no possibility of competing for shared data (escape analysis technique: all data on the heap does not escape to be accessed by other threads and can be treated as data on the stack).
3. Lock coarsening
If the virtual machine detects a string of fragmented operations that lock the same object, it will extend the scope of the lock step outside the entire operation sequence.
4. Lightweight locks
- If the synchronization object is not locked when the code enters the synchronization block, the virtual machine will first create a space called a Lock Record in the stack frame of the current thread to store a copy of the Mark Word in front of the object. The virtual machine then uses the CAS action to try to update the object’s Mark Word to a pointer that executes a Lock Record. If successful, the thread owns the lock on the object. If the update fails, the virtual machine first checks whether the Mark Word of the object refers to the stack frame of the current thread. If it does, the current thread has the lock on the object; otherwise, the object has been preempted by another thread. If there are more than two threads competing for the same lock, the lightweight lock is no longer valid and should be inflated to the heavyweight lock.
- Unlock process: if the product’s Mark Word still points to the lock record of the thread, the CAS operation will be used to replace the product’s current Mark Word and the product copied in the thread with the CAS operation. If the replacement is successful, the whole process will be completed. If this fails, another thread has attempted to acquire the lock, and the suspended thread must be awakened at the same time the lock is released.
- Rationale for lightweight locks: For the vast majority of locks, there is no contention for the entire synchronization cycle.
- Traditional locks (heavyweight locks) are implemented using operating system mutex.
The memory layout of the HotSpot VIRTUAL machine Object: The Object Header is divided into two parts of information, the first part (Mark Word) is used to store the Object’s own runtime data, and the other part is used to store the pointing method area A pointer to an object data type, if an array, has an extra part to store the length of the array.
In a 32-bit HotSpot VIRTUAL machine where objects are not locked, 25 Bits of Mark Word’s 32 Bits space are used to store object hash codes,4 Bits are used to store object generation ages,2 Bits are used to store lock flag Bits, and 1 bit is fixed to 0.
HotSpot VIRTUAL machine object header Mark Word
Store content | Sign a | state |
---|---|---|
Object hash code, object generation age | 01 | unlocked |
A pointer to a lock record | 00 | Lightweight locking |
Pointer to a heavyweight lock | 10 | Expansion (heavyweight lock) |
No information is recorded | 11 | The GC tag |
Bias to thread ID, timestamp, object generation age | 01 | Can be biased |
5. Biased locking
- The purpose is to eliminate synchronization primitives in the case of no contention and further improve the performance of the program. The lock is biased toward the first thread that acquired it, and if the lock is not acquired by another thread during subsequent execution, the thread that holds the lock will never need to synchronize again.
- When the lock is first acquired by the thread, the virtual machine will set the flag bit in the object header to 01, At the same time, the CAS operation is used to record the ID of the thread that obtained the lock in the Mark Word of the object. If successful, the thread holding the biased lock can not perform any synchronization operation every time it enters the lock related synchronization block.
- The bias mode ends when another thread attempts to acquire the lock. Unbias restores the lock to the unlocked or lightweight locked state, depending on whether the lock object is currently locked.
X. The difference between wait() and sleep()
- The two methods come from different classes. Sleep () comes from Thread and is a static method; Wait () is a method of the Object class that works with notify() or notifyAll() to communicate between threads.
- Sleep suspends the current thread for a specified time without releasing the lock. The wait method releases the lock, allowing other threads to use synchronized control blocks or methods.
- Use scope: Wait,notify, and notifyAll can only be used in synchronous control methods or synchronous control blocks, while sleep can be used anywhere.
Synchronized (x){x.notify() // or wait()}Copy the code
Note that sleep and wait must catch exceptions (both Thread.sleep() and Object.wait() throw InterruptedException), and notify and notifyAll do not.
After interruption () or isInterrupted() in Java, what is the difference?
Both methods are ways to determine whether a thread has stopped.
- The former is static and the latter is non-static. Interrupted applies to the currently running thread and isInterrupted applies to the thread of the thread object that called the method. The thread object does not necessarily correspond to the current running thread. For example, if you invoke the isInterrupted method in thread A, the current running thread is thread A.
- The former clears the interrupted state while the latter does not.
What is the difference between calling start() and run() directly after Java creates a thread?
- The start() method starts the thread and runs the run() method in a new thread, truly implementing multithreading. Instead of waiting for the body of the run method to finish executing, you can continue with the following code. A Thread is started by calling the start() method of the Thread class, which is ready but not running, and then by calling the run() method of the Thread class, which is called the Thread body, which contains the contents of the Thread to be executed. The run () method ends, and the thread terminates. The CPU then schedules other threads.
- When you call the run() method directly, it is called as if it were a normal method, executing the run() method in the current thread rather than starting a new thread to run the run() method. The program is also sequential execution, to wait for the run method body to complete execution, can continue to execute the following code; Only the main thread – this thread, the program execution path is only one, so that the purpose of multithreading is not achieved.
What is context switching for threads?
With a single-core CPU, the CPU can only run one thread at a time, and when running one thread switches to running another thread, this is called a thread context switch (similar for processes).
Data such as program counters and CPU registers are recorded during the thread context switch.
Although multithreading can improve the efficiency of task execution, but because of the same thread switching will bring a certain cost, and multiple threads will lead to an increase in the occupation of system resources, so in multithreading programming to pay attention to these factors.
How do I check if a thread has a lock?
There is a method called holdsLock(Object obj) in java.lang.Thread that returns true if and only if the current Thread has a lock on a specific Object.
What is the difference between a user thread and a daemon thread?
When we create a thread in a Java program, it is called a user thread. The way to set up a user thread as a daemon thread is to call the setDamon(true) method of the object before calling the start() method. A daemon thread is a thread that executes in the background and does not prevent the JVM from terminating. The purpose of a daemon thread is to facilitate the execution of other threads. When no user threads are running, the JVM closes the program and exits. A child thread created by a daemon thread is still a daemon thread.
A typical example of a daemon thread is the garbage collector.
What is a thread scheduler?
The Thread scheduler is an operating system service that allocates CPU time to Runnable threads. Once we create a thread and start it, its execution depends on the implementation of the thread scheduler.
Thread state.
Version 1.
In Java, threads typically have five states: created, ready, running, blocked, and dead.
- The first is to create state. When a thread object is generated, the object’s start method is not called, which is the thread being created.
- The second is readiness. When the start method of a thread object is called, the thread enters the current thread state, but the thread scheduler has not set the thread to the current thread. The thread is also in the ready state after it runs, after it comes back from waiting or sleeping.
- The third is the running state. The thread scheduler sets the thread in the ready state to the current thread, at which point the thread enters the run state and starts running the code in the run function.
- The fourth is blocking. A thread is suspended while it is running, usually to wait for something to happen (such as a resource to be ready) before continuing. Sleep,wait, and so on can cause a thread to block.
- The fifth is death. If a thread’s run method ends or is interrupted abnormally, the thread dies. For dead threads, you can no longer use the start method to get them ready.
Version 2.
In general, threads can be in the following states: created (new), ready (runnable), running (running), blocked (timed_waiting), waiting, and dead (dead).
There are three threads T1,T2,T3, how to ensure that they are executed in order?
The join () method.
19. In a main thread, a large number of threads are required to complete before the main thread is completed. Multiple ways, consider efficiency.
1. Use the join() method in the main function.
t1.start(); t2.start(); t3.start(); t1.join(); // Does not cause t2.join() to be executed in order of T1 and T2 and t3; t3.join(); System.out.println("Main finished");Copy the code
2. CountDownLatch, a synchronization helper class that allows one or more threads to wait until a set of operations that are being performed in other threads are complete.
public class WithLatch { public static void main(String[] args) { CountDownLatch latch = new CountDownLatch(3); for (int i = 0; i < 3; i++) { new ChildThead(i, latch).start(); } try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Main finished"); } static class ChildThead extends Thread { private int id = -1; private CountDownLatch latch = null; public ChildThead(int id, CountDownLatch latch) { this.id = id; this.latch = latch; } public void run() { try { Thread.sleep(Math.abs(new Random().nextint(5000))); System.out.println(String.format("Child Thread %dfinished", id)); } catch (InterruptedException e) { e.printStackTrace(); } finally { latch.countDown(); }}}}Copy the code
3. Use thread pools.
public class WithExecutor { public static void main(String[] args) throws InterruptedException { ExecutorService pool = Executors.newFixedThreadPool(3); List<Callable<Void>> list = new ArrayList<Callable<Void>>(); for (int i = 0; i < 3; i++) { list.add(new ChildThead(i)); } try { pool.invokeAll(list); } finally { pool.shutdown(); } System.out.println("Main finished"); } static class ChildThead implements Callable<Void> { private int id = -1; public ChildThead(int id) { this.id = id; } public Void call() throws Exception { try { Thread.sleep(Math.abs(new Random().nextint(5000))); System.out.println(String.format("Child Thread %dfinished", id)); } catch (InterruptedException e) { e.printStackTrace(); } return null; }}}Copy the code
Write in the last
As a Java programmer, want to enter BAT only learn multithreading is far from enough!
If you want to enter BAT, like Kafka, Mysql, Tomcat, Docker, Spring, MyBatis, Nginx, Netty, Dubbo, Redis, Netty, Spring Cloud, distributed, high concurrency, performance tuning, microservices and other architecture technology you have to learn!
Of course, the above technology can master 80 or 90 percent of the words, into Ali P7 or no big problem!
Need friends, pay attention to the below public number to receive!
Below are some screenshots of the interview questions