Uncle Ben's catalogue
ava concurrent programming
Why is it important
Concurrent programming can make full use of computer resources, maximize the performance of the computer, save the cost of the company and improve efficiency
1. What is high concurrency
The difference between concurrency and parallelism
Concurrent concurrency: multiple threads operate the same resource "at the same time", which is not really simultaneous operation, but alternating operation. In the case of single core CPU, resources are allocated to multiple threads according to time period (one processor handles multiple tasks)
Parallel parallelism: it is true that multiple threads execute at the same time, multi-core CPU, and each thread uses one CPU resource to run
Concurrent programming describes a design structure that allows the system to allow multiple tasks to be executed in overlapping time periods. It does not mean that multiple tasks are executed in the same time period, but that the system has the ability to process multiple tasks to be executed at the same time.
High concurrency means that the program we designed can support the execution of a large number of tasks in overlapping time periods.
High concurrency criteria:
- QPS: the number of HTTP requests responded per second. QPS is not a concurrent number
- Throughput: the number of requests processed per unit time, which is determined by QPS and concurrency
- Average response time: the average time the system takes to respond to a request
QPS = concurrency / average response time
- Number of concurrent users: the number of users carrying the system in normal use at the same time
Internet distributed architecture design, two ways to improve system concurrency:
- Vertical expansion
- Horizontal expansion
Vertical expansion
Improve stand-alone processing capacity (one computer)
-
1. Upgrade the stand-alone hardware equipment, increase the number of CPU cores, upgrade the network card, expand the capacity of hard disk and upgrade the memory
-
2. Improve the architecture performance of a single machine, use Cache to improve efficiency, use asynchronous requests to increase the throughput of a single service, and NoSQL to improve database access capability
Horizontal expansion
(multiple computers)
Cluster: one chef can't make it. Hire more chefs to cook together. Many people do the same thing.
Distributed: task segmentation, hire two assistants for the chef, one is responsible for washing vegetables, the other is responsible for cutting vegetables, and the chef is only responsible for cooking. A thing is divided into multiple steps and completed by different people.
Site layer extension: Nginx reverse proxy. If one Tomcat can't run, then 10 Tomcats will run
Service layer extension: RPC framework realizes remote call. Spring Cloud, Spring Boot, Dubbo and distributed architecture split business logic into different RPC clients to complete corresponding businesses. If a business has a large amount of concurrency, adding a new RPC Client can expand the performance of the service layer and achieve unlimited concurrency in theory
Expansion of data layer: in the case of a large amount of data, the original database server is divided into multiple servers, which has achieved the purpose of expanding the system performance, including master-slave replication, separation of reading and writing, separate tables and databases
2,JUC
JUC: import java.util.concurrent
A toolkit provided by JDK is specially used to help developers complete java Concurrent Programming
3. Processes and threads
The default number of threads in java is 2
-
Main main thread
-
GC garbage collection mechanism
java itself cannot start threads. java cannot operate hardware. It can only call local methods and the dynamic function library written in C + +
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (IMG zoqsidfk-16336717401240) (C: \ users \ Deku \ appdata \ roaming \ typora \ typora user images \ image-20210727165619657. PNG)]
There are several ways to implement multithreading in java
1. Inherit Thread class
2. Implement Runnable interface
3. Implement Callable interface
The difference between Callable and Runnable is that the run method of Runnable has no return value, and the call method of Callable has a return value
public class CallAble01 { public static void main(String[] args) throws ExecutionException, InterruptedException { testCallAble callAble = new testCallAble(); FutureTask<String> futureTask = new FutureTask<>(callAble); new Thread(futureTask).start(); String val = futureTask.get(); System.out.println(val); } } class testCallAble implements Callable<String>{ @Override public String call() throws Exception { System.out.println("Thread opened"); return "helloWord"; } }
-
Callable is not directly related to Thread, and Thread cannot be directly started by Thread (new Thread(callable).start()),
Because FutureTask is related to Runnable, you can use FutureTask to start threads
-
The following two are the two constructors of FutureTask
public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; // ensure visibility of callable }
public FutureTask(Runnable runnable, V result) { this.callable = Executors.callable(runnable, result); this.state = NEW; // ensure visibility of callable }
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-9blj6wp2-163367401242) (C: \ users \ Deku \ appdata \ roaming \ typora user images \ image-20210808154600828. PNG)]
- Resources and threads are bound, and the coupling degree is too high
public class Callable02 { public static void main(String[] args) { Account account = new Account(); new Thread(account,"A").start(); new Thread(account,"B").start(); } } class Account implements Runnable{ private static int num=0; @Override public synchronized void run() { num++; try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"Is the current second "+num+"Bit accessed"); } }
- decoupling
public class Callable03 { public static void main(String[] args) { Account01 account = new Account01(); new Thread(()->{ account.count(); },"A").start(); new Thread(()->{ account.count(); },"B").start(); } } class Account01{ private static int num=0; public synchronized void count() { num++; System.out.println(Thread.currentThread().getName()+"Is the current second "+num+"Bit accessed"); } }
4. Sleep and Wait
-
The difference between sleep and wait is that the two methods come from different classes, namely Thread and Object
-
Sleep is to sleep the current thread, and wait is to sleep the thread accessing the current object.
-
sleep will not release the lock, but wait will release the lock
-
sleep handles threads and wait handles resources
-
Since the thread waiting for a lock can resume operation only after obtaining the lock, it is very important to let the thread holding the lock release the lock in time when it does not need the lock. The thread holding the lock releases the lock when:
1. The synchronization method and code block of the current thread are released at the end of execution
2. When the current thread encounters a break or return in the synchronized method or synchronized code block, it is released when the code block or method is finally released.
3. It is released when the current thread has an unhandled error or exception leading to an abnormal end
4. Calling obj.wait() will immediately release the lock, and the current thread will pause and release the lock so that other threads can execute obj.notify(), but notify() will not immediately release the obj lock in sycronized(obj). The lock will not be released until the thread where notify() is located executes all the code in the synchronized(obj) block. While yield(),sleep() does not release the lock.
5. What is synchronized locked
1. When synchronized modifies a non static method, the caller of the method is locked
public class Callable04 { public static void main(String[] args) { Date date = new Date(); new Thread(()->{date.func1();},"AAA").start(); new Thread(()->{date.func2();},"BBB").start(); } } class Date{ public synchronized void func1() { try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("I'm number one"); } public synchronized void func2(){ System.out.println("I'm second"); } } /*Own understanding 1-Before locking, AAA waits for five seconds before entering the method, and BBB waits for three seconds, so BBB outputs first I'm second I'm number one 2-After locking, synchronized locks the caller of the method, that is, the date from new, AAA Go first and wait for five seconds. Because date is locked, BBB can only wait for AAA to finish before entering I'm number one I'm second */
2. When synchronized modifies a static method, it locks the class
public class Callable04 { public static void main(String[] args) { Date date = new Date(); Date date2 = new Date(); new Thread(()->{date.func1();},"AAA").start(); new Thread(()->{date2.func2();},"BBB").start(); } } class Date{ public synchronized static void func1() { try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("I'm number one"); } public synchronized static void func2(){ System.out.println("I'm second"); } } /* Because synchronized modifies a static method to lock a class, when thread AAA enters func1, class Data() is locked, So thread BBB has to wait, I'm number one I'm second */
3. synchronized static methods and instance methods exist at the same time. Static methods lock classes and instance methods lock objects
public class Callable04 { public static void main(String[] args) { Date date = new Date(); // Date date2 = new Date(); new Thread(()->{date.func1();},"AAA").start(); new Thread(()->{date.func2();},"BBB").start(); } } class Date{ public synchronized static void func1() { try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("I'm number one"); } public synchronized void func2(){ System.out.println("I'm second"); } } /* Because func1 is a static method, which locks classes, and func2 is an instance method, which locks instance objects, They manage their own and can't synchronize */
6,lock
- A locking mechanism provided by JUC has similar functions to synchronized. It is an upgrade of synchronized. It is an interface
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-ntoolrj-1633617401243) (C: \ users \ Deku \ appdata \ roaming \ typora user images \ image-20210808210609854. PNG)]
- Lock its implementation class
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-nwezteii-163367401244) (C: \ users \ Deku \ appdata \ roaming \ typora user images \ image-20210808210804354. PNG)]
-
His common implementation class is ReentrantLock
-
synchronized implements the locking mechanism through JVM, and ReentrantLock implements the locking mechanism through JDK
-
synchronized is a keyword and ReentrantLock is a class, which is essentially different
-
ReentrantLock is called reentrant lock in Chinese. As its name implies, multiple locks can be added to the same resource
-
Different unlocking methods:
- synchronized: automatically releases the lock after the thread is executed,
- ReentrantLock: manual unlocking is required
Classic case ticket selling
- synchronized lock for ticket selling
//Selling tickets public class lock01 { public static void main(String[] args) { Ticket ticket = new Ticket(); new Thread(()->{ for (int i = 0; i < 3000; i++) { ticket.sale(); }},"Zhang San").start(); new Thread(()->{ for (int i = 0; i <3000 ; i++) { ticket.sale(); }},"Li Si").start(); } } class Ticket{ private Integer saleNum=0;//Sell tickets private Integer lastNum=3000;//Remaining tickets public synchronized void sale(){ if(lastNum>0){ saleNum++; lastNum--; try { TimeUnit.MILLISECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"Sold"+saleNum+"Tickets, remaining"+lastNum); } System.out.println("-=---"); } }
- Ticket Locked lock
//Selling tickets public class lock01 { public static void main(String[] args) { Ticket ticket = new Ticket(); new Thread(()->{ for (int i = 0; i < 3000; i++) { ticket.sale(); }},"Zhang San").start(); new Thread(()->{ for (int i = 0; i <3000 ; i++) { ticket.sale(); }},"Li Si").start(); } } class Ticket{ private Integer saleNum=0;//Sell tickets private Integer lastNum=3000;//Remaining tickets private Lock lock=new ReentrantLock(); public void sale(){ lock.lock(); if(lastNum>0){ saleNum++; lastNum--; try { TimeUnit.MILLISECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"Sold"+saleNum+"Tickets, remaining"+lastNum); } lock.unlock(); System.out.println("-=---"); } } /* Of course, we can lock more than one lock, but we should pay attention to unlocking several times */
The difference between synchronized and Lock locks
1. synchronized is automatically locked and unlocked. Lock lock is manual locking and manual unlocking
2. synchronized is unable to determine whether a lock has been obtained. Lock can determine whether a lock has been obtained
3. synchronized will wait all the time if you can't get the lock. Lock doesn't necessarily wait all the time (tryLock is described below)
4. synchronized is the keyword and Lock is the interface
5. synchronized is a non fair lock. Lock can set whether it is a fair lock
private Lock lock=new ReentrantLock(true);
Fair lock: fair and queued. When the lock is not occupied, the current thread needs to judge whether there are other waiting threads in the queue
Unfair lock: unfair, queue jumping. When the lock is not occupied, the current thread can directly occupy it without judging whether there are waiting threads in the queue
Lock lock is recommended in actual development
- ReentrantLock is time limited. It can judge whether a thread can obtain a lock within a certain period of time. Using the tryLock method, it returns a Boolean type. true indicates that the lock can be obtained, and false indicates that the lock cannot be obtained
public class lock02 { public static void main(String[] args) { TimeOut timeOut = new TimeOut(); new Thread(()->{timeOut.timeLock();},"A").start(); new Thread(()->{timeOut.timeLock();},"B").start(); } } class TimeOut{ private ReentrantLock lock=new ReentrantLock(); public void timeLock(){ try { if(lock.tryLock(3, TimeUnit.SECONDS)){//Judge whether you can get the lock in three seconds System.out.println(Thread.currentThread().getName()+"Got the lock"); TimeUnit.SECONDS.sleep(5); }else{ System.out.println(Thread.currentThread().getName()+"I didn't get the lock"); } } catch (InterruptedException e) { e.printStackTrace(); } finally { if(lock.isHeldByCurrentThread()){//Determine whether the current thread holds this lock, lock.unlock(); } } } } /* lock.isHeldByCurrentThread()This method is the method in ReentrantLock, not the method in Lock This method indicates whether the current thread holds the lock */
Producer consumer model
synchronized
public class lock03 { public static void main(String[] args) { Data data = new Data(); new Thread(()->{ for (int i = 0; i <10 ; i++) { data.producers(); }},"A").start(); new Thread(()->{ for (int i = 0; i <10 ; i++) { data.consumers(); }},"B").start(); } } class Data{ private Integer num=0; public synchronized void producers(){ while(num!=0){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } num++; this.notify(); System.out.println(Thread.currentThread().getName()+"Produced:"+num+"Chicken"); } public synchronized void consumers(){ while(num==0){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }System.out.println(Thread.currentThread().getName()+"Consumed:"+num+"Chicken"); num--; this.notify(); } }
- You must use while to judge, not if, because if will cause false wake-up of threads. False wake-up means that some wait methods will be awakened except notify, not really.
Because if will be executed only once, the execution will be followed by the execution down to the outside of if ()
While does not, it will not execute the operation outside while () until the conditions are met
Lock
public class lock03 { public static void main(String[] args) { Data data = new Data(); new Thread(()->{ for (int i = 0; i <10 ; i++) { data.producers(); }},"A").start(); new Thread(()->{ for (int i = 0; i <10 ; i++) { data.consumers(); }},"B").start(); } } class Data{ private Integer num=0; private ReentrantLock lock=new ReentrantLock(); private Condition condition=lock.newCondition(); public void producers(){ lock.lock(); while(num!=0){ try { condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } } num++; condition.signal(); System.out.println(Thread.currentThread().getName()+"Produced:"+num+"Chicken"); if(lock.isHeldByCurrentThread()){lock.unlock();} } public synchronized void consumers(){ lock.lock(); while(num==0){ try { condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+"Consumed:"+num+"Chicken"); num--; condition.signal(); if(lock.isHeldByCurrentThread()){lock.unlock();} } }
- With Lock lock, you can't use wait and notify to pause and wake up threads. Instead, you should use await and signal of Condition to pause and wake up threads.
7,ConcurrentModificationException
Concurrent access exception (if there is no separation between reading and writing, an exception will be reported while reading and writing)
public class lock04 { public static void main(String[] args) { ArrayList<Object> list = new ArrayList<>(); for (int i = 0; i < 20; i++) { new Thread(()->{ try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } //write list.add("a"); //read System.out.println(Thread.currentThread().getName()+list); //Read / write a resource and report the exception at the same time },String.valueOf(i)).start(); } } } /* Modify a resource at the same time We can see that ArrayList is thread unsafe */
How to solve it?
1. Change a resource and replace the ArrayList with a Vector
Vector list = new Vector<>();
The add method of Vector has the synchronized keyword
x [the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-lmclo5ui-16336717401245) (C: \ users \ Deku \ appdata \ roaming \ typora \ user images \ image-20210809163211967. PNG)]
ArrayList is not synchronized, so its thread is unsafe
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-jjpcy567-163367401246) (C: \ users \ Deku \ appdata \ roaming \ typora user images \ image-20210809163527194. PNG)]
2. Use Collections.synchronizedList()
List<String> list= Collections.synchronizedList(new ArrayList<>());
This is a processing of ArrayList
3. JUC: CopyOnWriteArrayList (read write separation)
List<String> list = new CopyOnWriteArrayList();
-
// Source code of add method in CopyOnWriteArrayList public boolean add(E e) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray();//Copy the original array and put it in elements int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len + 1);//Define a new array, put elements in it, and count Group length plus 1 (to put e) newElements[len] = e;//Put the contents of add into the new array setArray(newElements);//Replace the new array with the original array (set) return true; } finally { lock.unlock(); } }
-
set
public class lock04 { public static void main(String[] args) { // Vector<String> list = new Vector<>(); // List<String> list= Collections.synchronizedList(new ArrayList<>()); Set<String> list = new CopyOnWriteArraySet<>(); for (int i = 0; i < 20; i++) { final int temp=i; new Thread(()->{ try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } //write list.add(String.valueOf(temp)+"a"); //read System.out.println(list); },String.valueOf(i)).start(); } } }
- Map
public class lock04 { public static void main(String[] args) { // Vector<String> list = new Vector<>(); // List<String> list= Collections.synchronizedList(new ArrayList<>()); Map<String,Object> map = new ConcurrentHashMap<>(); for (int i = 0; i < 10; i++) { final int temp=i; new Thread(()->{ try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } map.put(UUID.randomUUID().toString().substring(0,3),UUID.randomUUID().toString().substring(0,2)); System.out.println(map); },String.valueOf(i)).start(); } } } /* UUID.randomUUID().toString().substring(0,3) Generate a random number and take the first two digits. */
8. JUC tool class
-
CountDownLatch: subtraction counter
-
It can be used to count down. When two threads execute at the same time, if you want to ensure that one thread executes first, you can use the counter. When the counter is cleared, let another thread execute
-
new CountDownLatch(100), countDownLatch.countDown(), countDownLatch.await() must be used together. Count down() must be executed as many times as the value assigned during creation. Otherwise, the counter will not stop and other threads will not wake up. Therefore, it must be ensured that the counter is cleared and countDown() The number of calls must be greater than the parameter value of the constructor
-
public class JUC01 { public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(100); new Thread(()->{ for (int i = 0; i < 100; i++) { System.out.println("Thread thread ++++++++++++++"); countDownLatch.countDown(); } }).start(); countDownLatch.await(); for (int i = 0; i < 100; i++) { System.out.println("main thread +++++++++++"); } } } /* CountDownLatch.await() Method blocks the current thread before the countdown is 0. The counter stops and wakes up other threads */
- CyclicBarrier: addition counter
cyclicBarrier.await(); Try to wake up the counter thread in other threads. When the execution times of other threads reach the critical value of the counter, the counter thread will be awakened, and the counter can be reused. When the execution of the counter thread is completed once, the counter will be automatically cleared to wait for the next execution
public class JUC02 { public static void main(String[] args) { CyclicBarrier cyclicBarrier = new CyclicBarrier(20,()->{ System.out.println("Release-----------"); });//When the thread executes 30 times, it outputs once for (int i = 0; i < 100; i++) { final int temp=i; new Thread(()->{ try { cyclicBarrier.await(); System.out.println(temp); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } }).start(); } } } /* final int temp=i;The function of temp here is because the variables in lambda must be final or valid final */
- Semaphore: count semaphores
In the actual development, it is mainly used to complete the flow limiting operation and limit the number of threads that can access some resources
There are only three operations with Semaphore
1. Initialization
2. Obtaining permits
3. Release
When each thread executes, it first needs to obtain the semaphore. It can execute only after obtaining the resources. After execution, it needs to release the resources for the next thread.
public class JUC03 { public static void main(String[] args) { Semaphore semaphore = new Semaphore(5,true);//Initialization. The truth table is that it is a fair lock and can't jump the queue for (int i = 0; i < 20; i++) { new Thread(()->{ try { semaphore.acquire();//Get permission System.out.println(Thread.currentThread().getName()+"Go shopping"); TimeUnit.SECONDS.sleep(5); System.out.println(Thread.currentThread().getName()+"Go out"); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release();//release } },String.valueOf(i)).start(); } } }
9. Read write lock
It is an interface ReadWriteLock, and the implementation class is ReentrantReadWriteLock. It can be read by multiple threads at the same time, but only one thread can write at the same time.
Read / write locks are also used to achieve thread synchronization, but the granularity is finer. Different locks can be set for read and write operations respectively
A write lock is also called an exclusive lock, which can only be occupied by one thread. A read lock is also called a shared lock, which is occupied by multiple threads at the same time.
public class JUC04 { public static void main(String[] args) { ReadWrite readWrite = new ReadWrite(); for (int i = 0; i < 5; i++) { final int temp=i; new Thread(()->{ readWrite.write(temp,String.valueOf(temp)); },String.valueOf(i)).start(); } for (int i = 0; i < 5; i++) { final int temp=i; new Thread(()->{ readWrite.read(temp); },String.valueOf(i)).start(); } } } class ReadWrite{ private HashMap<Integer,String> map=new HashMap<>(); private ReadWriteLock readWriteLock=new ReentrantReadWriteLock(); public void write(Integer key,String value){ /* * write in * */ readWriteLock.writeLock().lock(); System.out.println(key+"Start writing"); map.put(key, value); System.out.println(key+"Write complete"); readWriteLock.writeLock().unlock(); } public void read(Integer key){ /* * read * */ readWriteLock.readLock().lock(); System.out.println(key+"Start reading"); map.get(key); System.out.println(key+"Read complete"); readWriteLock.readLock().unlock(); } }
10. Thread pool
A certain number of Thread objects are created in advance and stored in the buffer pool. When necessary, they are directly taken out of the buffer. After they are used up, they are not destroyed. They are returned to the buffer pool. In order to improve the utilization of resources - the idea of pooling
advantage
- Improve thread utilization
- Improve response speed
- Facilitate the same management thread object
- The maximum number of concurrent can be controlled
1. A certain number of Thread objects are created during thread pool initialization
2. If there is no idle thread object in the buffer pool, the new task enters the waiting queue
3. If there are no idle thread objects in the buffer pool and the waiting queue is full, you can apply to create a certain number of new thread objects until the maximum value of the thread pool is reached. At this time, if there are new tasks coming in, you can only choose to refuse
//Tool classes are not recommended for actual development public class pool01 { public static void main(String[] args) { //Singleton - open only one thread // ExecutorService executorService= Executors.newSingleThreadExecutor(); //Specifies the number of threads // ExecutorService executorService=Executors.newFixedThreadPool(5); //Cache thread pool, number of threads opened (Integer.MAX_VALUE) ExecutorService executorService=Executors.newCachedThreadPool(); for (int i = 0; i < 1000; i++) { final int temp =i; executorService.execute(()->{ System.out.println(Thread.currentThread().getName()+"----"+temp); }); } executorService.shutdown(); } } /* newSingleThreadExecutor newFixedThreadPool newCachedThreadPool These three tool classes are implemented through new ThreadPoolExecutor, so we should define them through new ThreadPoolExecutor in actual development, */
No matter what kind of thread pool is encapsulated by the tool class Executor, the underlying code is the same. The thread pool is built by creating a ThreadPoolExecutor object
- ThreadPoolExecutor source code
public ThreadPoolExecutor(int corePoolSize, //Core pool size, number of initialized threads int maximumPoolSize,//The maximum number of threads in the thread pool, which determines the upper limit of the thread pool long keepAliveTime,//survival time TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
-
corePoolSize: core pool size, number of initialized threads
-
maximumPoolSize: the maximum number of threads in the thread pool. It determines the upper limit of the thread pool
corePoolSize is the size of the thread pool. maximumPoolSize is a remedial measure when the number of tasks increases suddenly.
-
keepaliveTime: the lifetime of the thread object
-
Unit: thread object lifetime unit
-
workQueue: wait queue
-
threadFactory: thread factory, used to create thread objects
-
handler: reject policy (four types)
-
AbortPolicy: throw an exception directly
- java.util.concurrent.RejectedExecutionException
-
DiscardPolicy: discard the task without throwing an exception
-
DiscardOldestPolicy: try to compete with the top task in the waiting queue without throwing exceptions
-
CallerRunsPolicy: who calls and who handles
-
main=====>Handle business 5 pool-1-thread-3=====>Handle business 4 pool-1-thread-2=====>Handle business 1 pool-1-thread-1=====>Handle business 0 pool-1-thread-3=====>Handle business 2 pool-1-thread-1=====>Handle business 3
-
-
Custom thread pool
//Custom thread pool public class pool02 { public static void main(String[] args) { ExecutorService executorService=null; try { //Custom thread pool parameters executorService=new ThreadPoolExecutor( 2, 3, 1L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(2), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); for (int i = 0; i < 6; i++) { final int temp=i; executorService.execute(()->{ try { TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"=====>Handle the business"+temp); }); } } catch (Exception e) { e.printStackTrace(); } finally { executorService.shutdown(); } } } /* i=1,2,It means that 1 or 2 people handle business, meet the size of the core pool, and start the core thread according to the size of i i=3,4,It means that 3 or 4 people come to handle business. The core pool is full and enters the queue i=5. It means that five people come to handle business. The core pool is full and the queue is full. Only remedial measures can be started and another thread can be started i=6.It means that 6 people are handling business. The core pool is full and the queue is full, and it exceeds the upper limit of the thread pool, so the rejection policy can only be used The sixth person can only be shut out */
Three test sites of thread pool
1. Three implementations of Executors tool class
//Singleton - open only one thread ExecutorService executorService= Executors.newSingleThreadExecutor(); //Specifies the number of threads ExecutorService executorService=Executors.newFixedThreadPool(5); //Cache thread pool, number of threads opened (Integer.MAX_VALUE) ExecutorService executorService=Executors.newCachedThreadPool();
2. Seven parameters
int corePoolSize, //Core pool size, number of initialized threads int maximumPoolSize,//The maximum number of threads in the thread pool, which determines the upper limit of the thread pool long keepAliveTime,//survival time TimeUnit unit,//Thread object lifetime unit BlockingQueue<Runnable> workQueue,//Waiting queue ThreadFactory threadFactory,//Thread factory, used to create thread objects RejectedExecutionHandler handler//Reject policy
3. Four rejection strategies
- AbortPolicy: //Throw an exception directly - DiscardPolicy: //Abandon the task without throwing an exception - DiscardOldestPolicy: //Try to compete with the top task in the waiting queue without throwing exceptions - CallerRunsPolicy: //Who calls, who handles
11. ForkJoin framework
ForkJoin is a multithreaded concurrent processing framework released after JDK=1.7. Its function is similar to that of JUC. JUC often uses a single class to complete operations. ForkJoin uses multiple classes to complete a certain work at the same time, which is richer in processing than JUC. There are not many scenarios used in actual development. It will be used only when Internet companies really have high concurrent requirements, and points will be added in the interview
It is essentially a supplement to the thread pool and an extension of the function of the thread pool. Based on the thread pool, its core idea is to split a large task into many small tasks and execute them respectively. Finally, the results of small tasks are summarized to generate the final results
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-afmav3gx-163367401247) (C: \ users \ Deku \ appdata \ roaming \ typora user images \ image-20210810204734894. PNG)]
The essence is to split the task of a thread into multiple small tasks, then multiple tasks are executed concurrently, and finally the results are summarized.
For example, two threads a and B execute at the same time. A has more tasks and B has fewer tasks. B completes the task first. At this time, B helps a complete the task (take part of a to execute for a and summarize the results after execution), so as to improve efficiency. This is work stealing
work stealing
ThreadPoolExecutor the thread pool itself will not steal work (help each other). ForkJoin in order to improve efficiency,
The core of ForkJoin framework is two classes
- ForkJoinTask split task
- ForkJoinPool provides multithreaded concurrent work stealing.
The most important thing to use ForkJoinTask is to figure out how to split the task. The idea of recursion is used here.
1. ForkJoinTask task needs to be created. ForkJoinTask is an abstract class and cannot directly create an instance object of ForkJoinTask. We need to customize a class and inherit the ForkJoinTask subclass RecursiveTask. Recursive means recursion. This class provides the function of recursion
/* 10 Sum of billion */ public class ForkJoinTask01 extends RecursiveTask<Long> { private Long start; private Long end; private Long temp=100_0000L; public ForkJoinTask01(Long start, Long end) { this.start = start; this.end = end; } @Override protected Long compute() { if(end-start<temp){ Long sum=0L; for (Long i = start; i <= end; i++) { sum+=i; } return sum; }else{ Long avg=(start+end)/2; ForkJoinTask01 Task1 = new ForkJoinTask01(start,avg); Task1.fork(); ForkJoinTask01 Task2 = new ForkJoinTask01(avg+1,end); Task2.fork(); return Task1.join()+Task2.join(); } } }
public class Test { public static void main(String[] args) { long StartTimeMillis = System.currentTimeMillis(); ForkJoinPool joinPool = new ForkJoinPool(); ForkJoinTask01 task = new ForkJoinTask01(0L,10_0000_0000L); joinPool.execute(task); Long sun=0L; try { sun=task.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } long endTimeMillis = System.currentTimeMillis(); System.out.println(sun+"Yes"+(endTimeMillis-StartTimeMillis)); joinPool.shutdown(); } }
12. Volatile keyword
public class text01 { public static void main(String[] args) { List<String> list= new ArrayList<>(); for (int i = 0; i < 10; i++) { new Thread(()->{ list.add("a");//There are collections with the same output length because threads have opened up memory space System.out.println(list); }).start(); } } }
Volatile is a lightweight synchronization mechanism provided by the JVM. It is visible to the main memory object thread (understand what the main memory object thread is visible)
- What is memory visibility
- [the external chain image transfer fails, and the source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-zpsd8pse-163367401248) (C: \ users \ Deku \ appdata \ roaming \ typora \ user images \ image-20210811160413115. PNG)]
public class text02 { private static int num=0; public static void main(String[] args) { new Thread(()->{ while (num==0){ } }).start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } num=1; System.out.println(num); } } /* The thread copies a copy from the shared variable to the working memory From the above code, we can see that when num=0, the thread enters the where loop, but when we assign a value to num again and restart, the thread is still in the loop after the program outputs 1, which shows the visibility of memory. At the beginning, the thread gets the value from the shared variable and copies it to the working memory to enter the loop. When num=1, Our main thread copies the value of num and assigns num to 1. Therefore, the secondary thread does not exit the loop */
The function of Volatile is to jump the working memory and turn it into visibility. The main memory object thread is visible,
private static volatile int num=0;
Think about a question? If I don't use Volatile and I output it in where, will the thread stop?
while (num==0){ System.out.println("---"); }
-
Generally speaking, the thread will always loop out "-" and will not exit the loop, but we found that it will exit the loop after operation???
Why can't he perceive the change of num if there is no output in the loop? If there is a task in the loop, he can perceive the change of num
-
Because after a thread executes a task, it will save the variable back to main memory and read the latest value of the current variable from memory. If it is an empty task, it will not re read the value in memory
workQueue in thread pool
A blocking queue is used to execute the queue waiting for the specified. The commonly used blocking queues are as follows:
- ArrayBlockingQueue: array based first in first out queue. The size must be specified when creating.
- LinkBlockingQueue: a linked list based first in first out queue. It can be created without specifying the size. The default value is Integer.MAX_VALUE
- Synchronous queue: instead of saving the submitted task, it directly creates a new thread to execute the new task.
- PriorityBlockQueue: it is a blocking pair column with priority
Collection framework
Why use a collection framework?
1. The length of the array is fixed
2. An array cannot store multiple different data types at the same time
A collection is simply understood as a dynamic array whose length can be changed and can maintain any data type.
Set itself is one of the basic concepts of data structure. What we say here is the java language, which is the concrete implementation of this data structure.
The collection in java is not completed by a class, but a framework system composed of a group of interfaces and classes. It can be roughly divided into three layers. The top layer is a group of interfaces, followed by the implementation class of the interface.
Interface
- Collection: the most basic and top-level interface of the collection framework
- List: the sub interface of Collection. It is an ordered, non unique object and the most commonly used interface
- Set: the sub interface of Collection. It is an unordered and unique object
- Map: another interface independent of Collection, the top-level interface, stores a group of key value objects and provides key to value mapping
- Iterator: interface for outputting collection elements, generally used for unordered interfaces
- ListIterator: Iterator sub interface, which can output elements in a collection in both directions
- Enumeration: the traditional output interface has been replaced by Iterator
- SortedSet: the sub interface of Set, which can sort the elements in the Set
- SortedMap: the sub interface of Map, which can sort the elements in the collection
- Queue: queue interface.
- Map. Entry: the internal interface of map, which describes a set of key value pair elements stored in map
1. Collection interface
/* *@see Set * @see List * @see Map * @see SortedSet * @see SortedMap * @see HashSet * @see TreeSet * @see ArrayList * @see LinkedList * @see Vector * @see Collections * @see Arrays * @see AbstractCollection * @since 1.2 */ public interface Collection<E> extends Iterable<E> { // Query Operations
- The Iterable interface is the top-level interface, which implements the output of the collection
Collection is the most basic parent interface in the collection framework. It can store a group of unordered and non unique objects. Generally, it is not directly used or instantiated, but only used to provide specifications.
Collection is a sub interface of Iterable interface.
-
int size(); //Get collection length
-
boolean isEmpty(); //Determine whether the collection is empty
-
boolean contains(Object o); //Judge whether an object exists in the collection, including
-
Iterator<E> iterator(); //Instantiate the Iterator interface to traverse the collection
-
Object[] toArray(); //Converts a collection to an array
-
<T> T[] toArray(T[] a); //Converts the collection to an array of the specified data type
-
boolean add(E e); //Add elements to the collection
-
boolean remove(Object o); //Remove element from collection
-
boolean containsAll(Collection<?> c);//Determines whether all elements in another collection exist in the collection
-
boolean addAll(Collection<? extends E> //Adds all elements in a collection to the collection
-
boolean removeAll(Collection<?> c); //Removes all elements of an element from the collection
-
void clear(); //Clears all elements in the collection
-
boolean equals(Object o); //Judge whether two sets are equal
-
int hashCode(); //Returns the hash value of the collection
2. Collection sub interface
- List: used to store ordered, non unique elements
- Set: store unordered and unique elements
- Queue: queue interface
3. List interface
/* * @see Collection * @see Set * @see ArrayList * @see LinkedList * @see Vector * @see Arrays#asList(Object[]) * @see Collections#nCopies(int, Object) * @see Collections#EMPTY_LIST * @see AbstractList * @see AbstractSequentialList * @since 1.2 */ public interface List<E> extends Collection<E> { // Query Operations
In addition to inheriting the method of Collection
List common extension methods
-
E get(int index); //Returns the element at the corresponding position in the collection by subscript
-
E set(int index, E element); //Stores an object at a specified location in the collection
-
int indexOf(Object o); //Find the position of an object in the collection from front to back
-
int lastIndexOf(Object o); //Find the position of an object in the collection from back to front
-
ListIterator<E> listIterator(); //Instantiate the Iterator interface to traverse the collection
-
List<E> subList(int fromIndex, int toIndex); //Intercepting the List set by subscript
4. Implementation class of List interface
-
ArrayList: it is the most frequently used List implementation class in development. It implements arrays with variable length and allocates continuous space in memory, so it is fast to read and slow to add and delete
- Non thread safe.
-
Vector: thread safety, low efficiency, thread safety is realized directly through the synchronized keyword
list.add(1,"Hello 1 "); //Add a data at the position of 1 list.set(1,"Hello"); //Replace the value at position 1
- Stack: a subclass of Vector, which implements the data structure of the stack (first in and last out)
public class Collection02 { public static void main(String[] args) { Stack<String> stack=new Stack<>(); String push = stack.push("1");//Push System.out.println(push);//The output is 1 stack.add("2");//add is a method that inherits Vector and outputs a Boolean value stack.push("3"); System.out.println("Stack top element"+stack.peek()); System.out.println(stack); System.out.println("Stack top element"+stack.pop()); System.out.println(stack); System.out.println(stack.search("1")); } } /* peek():Copy the top element from the stack and output it pop():Take the top element directly from the stack Output: Stack top element 3 [1, 2, 3] Stack top element 3 [1, 2] */
Let's take a look at the source code of the stack.search method: it uses the lastIndexOf method of List to find the location of elements from back to front
public synchronized int search(Object o) { int i = lastIndexOf(o); if (i >= 0) { return size() - i; } return -1; }
- LinkedList: realize the first in first out queue and store it in the form of linked list.
The difference between ArrayList and LinkedList: the storage form in memory is different. ArrayList adopts the form of array and LinkedList adopts the form of linked list
The storage space of array in memory is continuous, fast to read and slow to add and delete.
Because the array is continuous in memory, the memory address of the target element can be quickly obtained according to the addressing formula (address=0000+4*n). Also, because the memory is continuous, adding or deleting elements must move the data, and the longer the array length, the more elements to move, and the slower the operation
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-6auqdy8q-163367401249) (C: \ users \ Deku \ appdata \ roaming \ typora \ user images \ image-20210812143701639. PNG)]
The linked list is discontinuous in memory, slow to read and fast to add and delete. The linked list is discontinuous in memory. There is no fixed formula to use. To read, you can only start from the first bit and traverse to the target element. The larger the data scale, the slower the operation.
Adding and deleting is fast, because you only need to reset the post pointers of the two nodes before and after the target element, which is independent of the data size
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-smz59u5l-163367401249) (C: \ users \ Deku \ appdata \ roaming \ typora user images \ image-20210812144733094. PNG)]
public class Collection03 { public static void main(String[] args) { LinkedList<String> linkedList = new LinkedList<>(); linkedList.add("1"); linkedList.add("2"); linkedList.offer("3"); System.out.println(linkedList);//[1, 2, 3] linkedList.push("4");//Added to the head of the linked list System.out.println(linkedList);//[4, 1, 2, 3] linkedList.addFirst("5"); System.out.println(linkedList);//[5, 4, 1, 2, 3] linkedList.addLast("7"); System.out.println(linkedList);//[5, 4, 1, 2, 3, 7] System.out.println(linkedList.peek());//5 System.out.println(linkedList.peekFirst());//5 System.out.println(linkedList.peekLast());//7 System.out.println(linkedList.pop());//5 System.out.println(linkedList);//[4, 1, 2, 3, 7] } }
Think about a question??
-
LinkedList and Stack both have pop() methods. What are their differences and similarities??
pop(): both methods take out the first element in the set, but the order of the two is opposite. Stack is "last in first out", so pop takes out the last element and LinkedList is "first in first out", so pop takes out the first element.
LinkedList implements the Deque interface, and Deque is the sub interface of queue. Queue is the queue. The bottom layer implements the data structure of the queue
In actual development, the Queue object cannot be instantiated directly.
The implementation class of Queue is AbstractQueue, which is an abstract class and cannot be instantiated directly. Its subclass PriorityQueue needs to be used in development
The data added in the Queue must be sequential.
public class Collection04 { public static void main(String[] args) { PriorityQueue<Object> priorityQueue = new PriorityQueue<>(); // priorityQueue.add("1"); // priorityQueue.add("2"); // priorityQueue.add("A"); // priorityQueue.add("B"); // priorityQueue.comparator(); priorityQueue.add(new A(1)); priorityQueue.add(new A(2)); System.out.println(priorityQueue); } } class A implements Comparable{ private int num; public A(int num){ this.num= num; } @Override public String toString() { return "A{" + "num=" + num + '}'; } @Override//compareTo comparison public int compareTo(Object o) { A a=(A)o; if (this.num>a.num) { return 1; }else if (this.num==num){ return 2; }else { return -1; } } }
Queue defaults to ascending and natural sorting of elements
5. Set interface
Like List, Set is the sub interface of Collection. The Set interface stores data in the form of hash, so the elements are out of order and can store a group of unordered and unique data
/* * @see Collection * @see List * @see SortedSet * @see HashSet * @see TreeSet * @see AbstractSet * @see Collections#singleton(java.lang.Object) * @see Collections#EMPTY_SET * @since 1.2 */ public interface Set<E> extends Collection<E> { // Query Operations
Set common implementation classes:
- HashSet
- LinkedHashSet
- TreeSet
HashSet: it is an implementation class that we often use in our development. It stores a group of unordered and unique objects.
Unordered: the storage order of elements is different from that of convenience.
public class Collection05 { public static void main(String[] args) { HashSet<Object> hashSet=new HashSet<>(); hashSet.add("C"); hashSet.add("A"); hashSet.add("B"); System.out.println(hashSet);//[A, B, C] hashSet.remove("B"); } }
LinkedHashSet is another implementation class of Set, which can store an ordered and unique Set of elements
Order: the storage order of elements is consistent with the convenient order
public class Collection { public static void main(String[] args) { LinkedHashSet<Object> set=new LinkedHashSet<>(); set.add("b"); set.add("a"); set.add("c"); System.out.println(set);//[b, a, c] set.spliterator().forEachRemaining((n)->{ System.out.println(n);//b a c }); } }
- Think about the difference between equals and =???
Equals in all classes inherit the Object class. The native equals method in Object is judged by = =
/* * @see java.util.HashMap */ public boolean equals(Object obj) { return (this == obj); }
However, each class can override the equals method, override the previous = = to make a logical judgment, and use the new logic to judge whether it is equal.
How does the LinkedHashSet determine whether two objects are equal?
First, it will judge whether the hashcodes of the two objects are equal
What is HashCode?
Convert the internal information (memory address, attribute value, etc.) of the object into a hash value through a specific rule, which is the HashCode of the object.
new A(2).hashCode()
- The hashCode values of two different objects may be equal
- Two objects with unequal hashcodes must not be the same object
When judging whether two objects are equal, the collection will first compare their hashcodes. If the hashcodes are not equal, it is considered that they are not the same object and can be added.
If the hashCode values are equal, it cannot be considered that the two objects are equal. Further judgment needs to be made through equals. If equals, the two objects are equal, otherwise the two objects are not equal
==: determines the value in the stack memory
For data of reference type, the address is stored in the stack memory, so at this time = = determines the reference address.
Basic data type. Specific values are stored in stack memory
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-ilmv1uui-163367401250) (C: \ users \ Deku \ appdata \ roaming \ typora \ typora user images \ image-20210815075023283. PNG)]
Variables are stored in the stack
Data data; The specific object (attribute) of the reference type is stored in the heap, and then the memory address of the object in the heap is assigned to the variable data in the stack. What is stored in data is the address
int num; The basic data type does not need heap memory. The variable is on the stack, and the value of the variable is directly stored on the stack.
6,TreeSet
LinkedHashSet and TreeSet are stored in an ordered and unique set of data, but the two orders here are different
The order of LinkedHashSet means that the storage order of elements is the same as the traversal order
The order of TreeSet means that all elements in the collection will be automatically sorted in ascending order. No matter what the storage order is, it must be output in ascending order during traversal (sorted according to ASCII code)
/* * @see Collection * @see Set * @see HashSet * @see Comparable * @see Comparator * @see TreeMap * @since 1.2 */ public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, java.io.Serializable {
public class Collection01 { public static void main(String[] args) { TreeSet<Object> treeSet = new TreeSet<>(); // treeSet.add("BCBC"); // treeSet.add("CC"); // treeSet.add("AC"); // treeSet.add("AB"); // treeSet.add("AA"); // treeSet.add("BCBD"); treeSet.add(new Data(1)); treeSet.add(new Data(3)); treeSet.add(new Data(2)); treeSet.add(new Data(1)); System.out.println(treeSet); Iterator iterator=treeSet.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } } } class Data implements Comparable{ private int num; public Data(int num) { this.num = num; } /* * A.compareTo(B) *Return value * 1: Indicates that A is greater than B * 0: Indicates that A equals B * -1: Indicates that A is less than B * */ @Override//compare ratio size public int compareTo(Object o) { if(o instanceof Data){ Data data=(Data)o; if(this.num>data.num){ return 1; }else if (this.num==data.num){ return 0; }else{ return -1; } } return 0; } @Override public String toString() { return "Data{" + "num=" + num + '}'; } }
7,Map
Key value: data dictionary,
The List and Set interfaces are all sub interfaces of the Collection. The Map interface is a completely independent system from the Collection.
List & Set VS Map
List & Set & collection can only operate on a single element. Map can operate on a pair of elements because the map operation space is a key value mapping.
/* * @see HashMap * @see TreeMap * @see Hashtable * @see SortedMap * @see Collection * @see Set * @since 1.2 */ public interface Map<K,V> { // Query Operations
The Map interface uses generics and defines two generics K and V. K represents Key, specifies the data type of Key element, and V represents the data type of Value element
-
int size();
-
boolean isEmpty();
-
boolean containsKey(Object key); //Determine whether the set contains a key
-
boolean containsValue(Object value);//Judge whether the collection contains Value
-
V get(Object key);//Get the Value corresponding to the key in the collection
-
V put(K key, V value);//Store a set of key values into the collection
-
V remove(Object key);//Delete the value corresponding to the key in the collection
-
void putAll(Map<? extends K, ? extends V> m);//Add another Map to the collection
-
void clear();//Clear all elements in the collection
-
Set<K> keySet();//Take out all Key values in the Set and return a Set
-
Collection<V> values();//Take out all value s in the Collection and return a Collection
-
Set<Map.Entry<K, V>> entrySet();//Output Map as Set
-
int hashCode();//Gets the hash value of the collection
-
boolean equals(Object o);//Compare two sets for equality
8. Common implementation classes of Map interface
- HashMap: stores a group of unordered elements whose keys cannot be repeated and whose values can be repeated
- Hashtable: stores a group of unordered elements whose keys cannot be repeated and whose values can be repeated
- TreeMap: stores a group of elements that are ordered, whose keys cannot be repeated, and whose values can be repeated. They can be sorted by Key
The usage of Hashtable is basically the same as that of HashMap. The difference is that Hashtable is thread safe and has low performance. HashMap is non thread safe, but has high performance
- The HashMap method is not decorated with synchronized, so it is non thread safe,
public V put(K key, V value) { return putVal(hash(key), key, value, false, true); }
- Hashtable, the method is decorated with synchronized, so it is thread safe
public synchronized V put(K key, V value) { // Make sure the value is not null if (value == null) { throw new NullPointerException(); } // Makes sure the key is not already in the hashtable. Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> entry = (Entry<K,V>)tab[index]; for(; entry != null ; entry = entry.next) { if ((entry.hash == hash) && entry.key.equals(key)) { V old = entry.value; entry.value = value; return old; } } addEntry(hash, key, value, index); return null; }
The data saved by HashMap and Hashtable are out of order. Another implementation class of Map, TreeMap, is mainly used to sort the elements in the collection according to the Key.
9. Collections tool class
Collection interface, parent interface of List and Set.
Collections is not an interface, but a tool class. It provides some operations on collections to facilitate developers to use and complete corresponding business functions.
Collections tool class for collections, Collection
Arrays tool class for arrays, Array
-
public static sort();//Sort collection
-
public static int binarySearch(List list,Object v);//Find the position of v in the combination. The set must be sorted in ascending order and binary search
-
private static get(List list, int index) //Returns the value of index in the collection
-
public static void reverse(List<?> list)//Output the set in reverse order
-
public static void swap(List<?> list, int i, int j)//Swaps two elements at a specified location in a collection
-
public static <T> void fill(List<? super T> list, T obj)//The data type of T is formed by combining the replacement of all elements in the
-
public static T min(Collection<? extends T> coll) //Returns the minimum value in the collection
-
public static T max(Collection<? extends T> coll, Comparator<? super T> //Returns the maximum value in the collection
-
public static <T> boolean replaceAll(List<T> list, T oldVal, T newVal)//Replace old with new in the List
-
public static <T> boolean addAll(Collection<? super T> c, T... elements)//Add a meta to the collection
Variable parameters. When calling the method again, the parameters can be any number, but the types must match
public static void test(int... arg){ }
However, the following expression can pass any type and any number of parameters, a specific form of polymorphism
public static void test(Object... arg){ }
The default output object format in Java: the full class name (fully qualified class name) to which the object belongs, the class name with package name + @ + the hash value of the object
JavaScript scripting language line by line compilation
Java must be compiled and executed uniformly. If there are ten lines of Java code, these 10 lines of code must be compiled and passed before being handed over to the JVM for execution
JS is executed line by line, and each line is counted as one line. If there are 10 lines of JS code, the execution starts line by line, and an error is reported until the fifth line, then lines 6-10 will not be executed, but the results of the first five lines that have been executed remain unchanged.
public class demo01 { public static void main(String[] args) { ArrayList<String> list=new ArrayList<>(); list.add("Hello"); list.add("Word"); Collections.addAll(list,"JavaEE","JavaME","Java"); System.out.println(list);//[Hello, Word, JavaEE, JavaME, Java] Collections.sort(list); System.out.println(list);//[Hello, Java, JavaEE, JavaME, Word] //Binary search, binary search (the elements in the collection must be arranged in ascending order) int binarySearch = Collections.binarySearch(list, "Java"); System.out.println("Java Subscript of"+binarySearch);//Subscript 1 of Java Collections.replaceAll(list,"Hello","Word"); System.out.println(list);//[Word, Java, JavaEE, JavaME, Word] } }
generic paradigm
Generics means that the data type of the information in the class is not specified during class definition, but is temporarily replaced by an identifier, and the specific data type is specified when the object is instantiated externally
//The type of a is specified when defining class A public class A{ private int a; }
//When defining class A, the type of attribute is not specified public class A<TE,M>{ private T b; public E B(M m){ return E; } } //When called A<T,E,M> a=new A<>();
Advantages: this greatly improves the flexibility of the program and the extensibility of the class. Generics can refer to the data types of member variables in the class, the return value types of methods and the parameter types of methods.
1. Application of generics
Add generics to custom classes
public class Class name<Generic 1, generic 2, generic 3...>{ private Generic 1 property name; public Generic 2 method name(Generic 3){ Method body; } }
public class Generics01 { public static void main(String[] args) { Time<Integer,String,Float> time=new Time<>(); time.setHello(1); time.setWord("Hello"); time.setJava(1.1f); System.out.println(time);//Time{Hello=1, Word = Hello, Java=1.1} } } class Time<T,E,M>{ private T Hello; private E Word; private M Java; @Override public String toString() { return "Time{" + "Hello=" + Hello + ", Word=" + Word + ", Java=" + Java + '}'; } public T getHello() { return Hello; } public void setHello(T hello) { Hello = hello; } public E getWord() { return Word; } public void setWord(E word) { Word = word; } public M getJava() { return Java; } public void setJava(M java) { Java = java; } }
2. Generic wildcard
There is a method whose parameter is ArrayList. We hope that this method can accept both sets whose generic type is String and sets whose generic type is Intger. How to implement??
- Polymorphism is not used in generics
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-0nnsdb9x-163367401250) (C: \ users \ Deku \ appdata \ roaming \ typora \ user images \ image-20210819144905021. PNG)]
public class generics02 { public static void main(String[] args) { ArrayList<String> arrayList=new ArrayList<>(); ArrayList<Integer> arrayList1=new ArrayList<>(); Test(arrayList); Test(arrayList1); } public static void Test(ArrayList<?> arrayList){} }
ArrayList<?> Represents an object that can use any generic type, so test has generality.
3. Upper and lower bounds of generics
- Upper limit: represents the specific data type during instantiation. It can be a subclass of the upper limit type or the upper limit type itself. It is represented by extensions
- Lower bound: represents the specific data type during instantiation. It can be the parent of the lower bound type or the lower bound type itself. It is represented by super
Class name<Generic identity extends Upper class name>
Class name<Generic identity super Lower bound class name>
public class generics03<T> { public static void main(String[] args) { test(new generics03<Integer>()); test(new generics03<Float>()); test(new generics03<Number>()); //--------------------------------- test1(new generics03<String>()); test1(new generics03<Object>()); } /* * Generic upper bound * */ public static void test(generics03<? extends Number> generics03){} /* * Generic lower bound * */ public static void test1(generics03<? super String> generics03){} }
4. Generic interface
Interface < >
public interface generics04<T> { public T getValue(); }
There are two ways to implement generic interfaces
- Implementation classes continue to use generic IDS when defining
public class generics04Impl<T> implements generics04{ private T obj; public generics04Impl(T obj) { this.obj = obj; } @Override public T getValue() { return this.obj; } }
- The implementation class directly gives the specific data type when defining
public class generics04Impl01 implements generics04<String> { private String Obj; public generics04Impl01(String obj){ this.Obj=obj; } @Override public String getValue() { return this.Obj; } }
public class generics04VO { public static void main(String[] args) { generics04Impl generics=new generics04Impl<String>("Hello"); System.out.println(generics.getValue()); generics04Impl01 generics2=new generics04Impl01("world"); System.out.println(generics2.getValue()); } }
Java utility class
Similar to Arrays, Collections
1. Enumeration
Enum enum is a data type with definite value interval. It is essentially a class with the characteristics of simplicity, convenience and security
The value of enumeration is constrained to a specific range and can only be taken from this range
Why are there enumerations??????????
Because when describing the attributes of some objects, the value of the attribute cannot be defined arbitrarily, but must be taken in a specific interval
For the sake of data security, we can use enumeration to describe such data with specific value range
Enumeration refers to a type composed of a group of constants. It specifies a value range from which we can only take values
public enum Week { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY; }
final class Week extends Enum{ public static final Week MONDAY; public static final Week TUESDAY; public static final Week WEDNSDAY; public static final Week THURSDAY; public static final Week FRIDAY; public static final Week SATURDAY; public static final Week SUNDAY; private static final Week $VALUES[]; static{ MONDAY = new Week("MONDAY",0); TUESDAY = new Week("TUESDAY",1); WEDNSDAY = new Week("WEDNSDAY",2); THURSDAY = new Week("THURSDAY",3); FRIDAY = new Week("FRIDAY",4); SATURDAY = new Week("SATURDAY",5); SUNDAY = new Week("SUNDAY",6); $VALUES[] = (new Week[]{ MONDAY,TUESDAY,WEDNSDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY }) } public static Week[] values(){ return $VALUES.clone(); } public static Week valueOf(String s){ return Enum.valueOf(s); } private Week(String s,int i){ super(s,i); } }
2,Math
The Math class provides for developers
public class Test { public static void main(String[] args) { System.out.println("constant E: "+Math.E);//Constant E: 2.718281828459045 System.out.println("constant PI: "+Math.PI);//Constant PI: 3.141592653589793 System.out.println("9 Square root of:"+Math.sqrt(9));//Square root of 9: 3.0 System.out.println("8 Cube root of:"+Math.cbrt(8));//Cube root of 8: 2.0 System.out.println("2 Third power of:"+Math.pow(2,3));//Power 3 of 2: 8.0 /* * Here, the 1 of int type is automatically converted to double type and becomes 1.0 * Type conversion has only cast and automatic conversion * */ System.out.println("Larger value:"+Math.max(6.5, 1));//Larger value: 6.5 System.out.println("Absolute value:"+Math.abs(-1));//Absolute value: 1 System.out.println(Math.ceil(10.0000001));//11.0 System.out.println(Math.floor(10.999999));//10.0 //0<Math.random()<1 System.out.println("Random number:"+Math.random());//Random number: 0.71382027555706 System.out.println("Random number:"+ (int) (Math.random() * 10));//Random number: 1 System.out.println("rounding:"+Math.rint(5.5));//6.0 } }
3,Random
The class used to generate random numbers, and any interval can be specified to generate a random number within this interval
-
public Random();//Create a nonparametric random number constructor, using system time as the default seed
-
public Random(Long seed);//Create a random number constructor using a seed of type Long
-
public boolean nextBoolean();//Returns a random number of Boolean type
-
public double nextDouble();//Returns a random number of double type, between 0.0 and 1.0
-
public float nextFloat();//Returns a random number of float type, between 0.0 and 1.0
-
public int nextInt();//Returns an integer of type int
-
public int nextInt(n);//Returns a random number from 0 to N, [0,n)
name describe public static sort() Sort collection public static int binarySearch(List list,Object v) To find the position of v in the list, the set must be ordered public static get(List list,int index) Returns the value of the index position in the list public static void reverse(List list) Output the list in reverse order public static void swap(List list,int i,int j) Swaps two elements at a specified location in a collection public static void fill(List list,Object obj) Replace all elements in the collection with obj public static Object min(List list) Returns the minimum value in the collection public static Object max(List list) Returns the maximum value in the collection public static boolean replaceAll(List list,Object old,Object new) Replace old with new in the list set public static boolean addAll(List list,Object... obj) Add elements to the collection
4,String
java uses the String class to create and manipulate strings
- String instantiation
1. Direct assignment
String str="HelloWord";
2. Create objects through constructors
String str=new String("HelloWord");
public class Test{ public static void main(String[] arg){ String str="Hello"; String Str2=new String("Hello"); System.out.println(str==str2);//false System.out.println(str.equals(str2)));//ture } }
String is not a basic data type
5. Common methods of String
method | describe |
---|---|
public String() | Create an empty string object |
public String(String value) | Create a string object with value |
public String(char value[]) | Converts a char array to a string object |
public String(char value[],int offset, int count) | Converts a char array of a specified range to a string object |
public String(byte value[]) | Converts a byte array to a string object |
public String(byte value[],int offset, int count) | Converts a byte array of a specified range into a string object |
public int length() | Gets the length of the string |
public boolean isEmpty() | Determine whether the string is empty |
public char charAt(int index) | Returns the character of the specified subscript |
public byte[] getBytes() | Returns the byte array corresponding to the string |
public boolean equals(Object anObject) | Judge whether two string values are equal |
public boolean equalsIgnoreCase(Object anObject) | Judge whether two string values are equal (case ignored) |
public int compareTo(String value) | Sort strings |
public int compareToIgnoreCase(String value) | Sort regardless of case |
public boolean startsWith(String value) | Determines whether the string starts with value |
public boolean endsWith(String value) | Determines whether the string ends with value |
public int hashCode() | Returns the hash value of a string |
public int indexOf(String str) | Returns the subscript of str in a string |
public int indexOf(String str,int formIndex) | Finds the subscript of a string from the specified location |
public String subString(int beginIndex) | Intercepts the string from the specified location |
public String subString(int beginIndex,int endIndex) | Intercepts the string of the specified interval |
public String concat(String str) | Append string |
public String replaceAll(String o,String n) | Replace all o's in the string with n's |
public String[] split(String regex) | Splits the target with the specified string and returns an array |
public String toLowerCase() | Turn lowercase |
public String toUpperCase() | Capitalize |
public char[] toCharArray() | Convert string to character array |
6,StringBuffer
Once a String object is created, its value cannot be modified (the original value cannot be modified. Once it is modified, it will be a new object. As long as it is changed, a new object will be created)
After modification, the memory space will be reopened to store the new object.
Why can't the value of String be modified? Will a new object be created after modification? Instead of modifying the original object?
- Because the underlying String uses an array to store values, the length of the array cannot be modified once it is created, resulting in the above problems
StringBuffer can solve the problem of wasting space resources caused by frequent String modification.
The underlying layer of StringBuffer also uses arrays to store values
- The default length of the StringBuffer array is 16, and the parameterless structure is used to create objects
public StringBuffer() { super(16); }
- Create an object using a parameterized construct. Array length = length of value + 16
public StringBuffer(int capacity) { super(capacity); }
public StringBuffer(String str) { super(str.length() + 16); append(str); }
public StringBuffer(CharSequence seq) { this(seq.length() + 16); append(seq); }
Append, append and splice
public class Random01 { public static void main(String[] args) { StringBuffer stringBuffer=new StringBuffer(); StringBuffer stringBuffer1=new StringBuffer("String"); /*stringBuffer Bottom array length 16 * stringBuffer1 Underlying array length 21 * */ stringBuffer.append("String"); System.out.println(stringBuffer1.equals(stringBuffer));//false System.out.println(stringBuffer1.toString().equals(stringBuffer.toString()));//true System.out.println(stringBuffer.length());//6 System.out.println(stringBuffer1.length());//6 } }
- The. length() method returns not the length of the underlying array, but its effective length (the length of the value)
reflection??? Once the StringBuffer is created, there will be 16 bytes of space to modify by default. However, how to deal with it once the length of the appended string exceeds 16??
StringBuffer will not reopen a new space, but will expand the capacity on the original basis. It will expand the capacity of the underlying array by calling the parent class ensureCapacityInternal() method, leaving the reference unchanged
stringBuffer.ensureCapacity(1);
StringBuffer is a common method. StringBuffer is thread safe but inefficient. StringBuilder is thread unsafe but efficient.
HashMap: unsafe thread and high efficiency
Hashtable: thread safe and inefficient
method | describe |
---|---|
public StringBuffer() | Create an empty StringBuffer object |
public StringBuffer(String str) | Create a StringBuffer object with the value str |
public synchronized int length() | Returns the length of the StringBuffer |
public synchronized char charAt(int index) | Returns the character at the specified position |
public synchronized StringBuffer append(String str) | Additional content |
public synchronized StringBuffer delete(int start,int end) | Deletes the value of the specified interval |
public synchronized StringBuffer deleteCharAt(int index) | Deletes the character at the specified position |
public synchronized StringBuffer replace(int start,int end,String str) | Replace the value of the specified interval with str |
public synchronized String substring(int start) | Intercepts the string from the specified position to the end |
public synchronized String substring(int start,int end) | The intercepted string starts from start and ends at end |
public synchronized StringBuffer insert(int offset,String str) | Insert str at the specified location |
public int indexOf(String str) | Finds the position of the specified character from scratch |
public int indexOf(String str,int fromIndex) | Finds the position of the specified character starting from fromIndex |
public synchronized StringBuffer reverse() | Reverse |
public synchronized String toString() | Convert to String |
Reading data does not need to consider thread safety, because there is no security risk in this operation.
Date class
- java.util.Date
Date indicates the current system time
public class Data01 { public static void main(String[] args) { Date date = new Date();//Wed Aug 25 15:32:56 CST 2021 /* * h It's 12 hour hh:mm:ss * H It is 24-hour HH:mm:ss * */ SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); String str = simpleDateFormat.format(date);//2021-08-25 03:35:34 } }
- java.util.Calendar
Calendar is used to complete the logical operation of date data
Operation idea:
1. Transfer date data to Calendar (Calendar provides many static constants, which are specially used to record date data)
constant | describe |
---|---|
public static final int YEAR | year |
public static final int MONTH | month |
public static final int DAY_OF_MONTH | Days in months |
public static final int DAY_OF_YEAR | Days in years |
public static final int HOUR_OF_DAY | hour |
public static final int MINUTE | minute |
public static final int SECOND | second |
public static final int MILLSECOND | millisecond |
2. Call relevant methods for operation
method | describe |
---|---|
public static Calendar getInstance() | Get Calendar instantiation object |
public void set(int field,int value) | Assign values to static constants |
public int get(int field) | Gets the value of a static constant |
public final Date getTime() | Convert Calendar to Date object |
public class Calendar01 { public static void main(String[] args) { SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd"); //Calculate the week today is the week of 2021 Calendar calendar=Calendar.getInstance(); System.out.println(format.format(calendar.getTime()));//2021-08-25 current time calendar.set(Calendar.YEAR,2021); calendar.set(Calendar.MONTH,7);//January is zero and August is seven calendar.set(Calendar.DAY_OF_MONTH,24); int week = calendar.get(Calendar.WEEK_OF_YEAR); System.out.println(week);//35 //What month is the 63 days after today int day=calendar.get(Calendar.DAY_OF_YEAR); System.out.println(day);//Today is the first day of several years 236 day+=63; calendar.set(Calendar.DAY_OF_YEAR,day); Date date=calendar.getTime(); System.out.println(format.format(date));//2021-10-26 //What month is the 63 days before today calendar.set(Calendar.DAY_OF_YEAR,calendar.get(Calendar.DAY_OF_YEAR)-63); date=calendar.getTime(); System.out.println(format.format(date));//2021-08-24 } }
IO stream
1. File class
- java.io.File use the constructor of this class to create a constructor to represent a specific file in the hard disk as a java object
method | describe |
---|---|
public File(String pathname) | Create objects from paths |
public String getName() | Get file name |
public String getParent() | Get the directory where the file is located |
public File getParentFile() | Get the File object corresponding to the directory where the File is located |
public String getPath() | Get file path |
public boolean exists() | Determine whether the file exists |
public boolean isDirectory() | Determine whether the object is a directory |
public boolean isFile() | Judge whether the object is a file |
public long length() | Gets the size of the file |
public boolean createNewFile() | Creates a new file based on the current object |
public boolean delete() | delete object |
public boolean mkdir() | Create a directory based on the current object |
public boolean renameTo(File file) | Rename an existing object |
- According to the direction, it can be divided into input flow and output flow
- According to the unit, it can be divided into byte stream and character stream
- According to the function, it can be divided into node flow and processing flow
2. Byte stream
According to the direction, it can be divided into input byte stream and output byte stream
InputSteam,OutputSteam
1 byte = 8-bit binary number 01010101
Common methods of InputStream
method | describe |
---|---|
int read() | Read data in bytes |
int read(byte b[]) | Store data into an array of byte type and return the length of valid data in the array |
int read(byte b[],int off,int len) | Store the data into the specified interval of byte array and return the length of the array |
byte[] readAllBytes() | Store all data into byte array and return |
int available() | Returns the number of unread data in the current data stream |
void close() | Close data flow |
OutputStream
method | describe |
---|---|
void write(int b) | Output data in bytes |
void write(byte b[]) | Output data from byte array |
void write(byte b[],int off,int len) | Outputs the data of the specified interval in the byte array |
void close() | Close data flow |
void flush() | Synchronize the data in the buffer stream to the output stream |
//What month is the 63 days before today calendar.set(Calendar.DAY_OF_YEAR,calendar.get(Calendar.DAY_OF_YEAR)-63); date=calendar.getTime(); System.out.println(format.format(date));//2021-08-24 }
}
# IO stream ## 1. File class - [ ] java.io.File Using the constructor of this class, you can create a constructor to convert a specific file in the hard disk to java Object | method | describe | | ---------------------------------- | ------------------------------ | | public File(String pathname) | Create objects from paths | | public String getName() | Get file name | | public String getParent() | Get the directory where the file is located | | public File getParentFile() | Get the corresponding directory of the file File object | | public String getPath() | Get file path | | public boolean exists() | Determine whether the file exists | | public boolean isDirectory() | Determine whether the object is a directory | | public boolean isFile() | Judge whether the object is a file | | public long length() | Gets the size of the file | | public boolean createNewFile() | Creates a new file based on the current object | | public boolean delete() | delete object | | public boolean mkdir() | Create a directory based on the current object | | public boolean renameTo(File file) | Rename an existing object | - According to the direction, it can be divided into input flow and output flow - According to the unit, it can be divided into byte stream and character stream - According to the function, it can be divided into node flow and processing flow ## 2. Byte stream According to the direction, it can be divided into input byte stream and output byte stream InputSteam,OutputSteam 1 byte = 8 Bit binary number 01010101 InputStream common method | method | describe | | ---------------------------------- | ------------------------------------------------------ | | int read() | Read data in bytes | | int read(byte b[]) | Store data in byte Returns the length of valid data in the array | | int read(byte b[],int off,int len) | Store data in byte Returns the length of the array within the specified interval of the array | | byte[] readAllBytes() | Store all data in byte Array and return | | int available() | Returns the number of unread data in the current data stream | | void close() | Close data flow | OutputStream | method | describe | | ------------------------------------ | ------------------------------ | | void write(int b) | Output data in bytes | | void write(byte b[]) | take byte Data output in array | | void write(byte b[],int off,int len) | take byte Data output of the specified interval in the array | | void close() | Close data flow | | void flush() | Synchronize the data in the buffer stream to the output stream |