2022-08-04 Group 5 Zhang Mingmin study notes

Table of contents

1. LockSupport tool class

1. Lock

2. Thread pool

1. Why use thread pool

2. The meaning of the parameters (important):

3. Common work queues

4. The thread pool provides four rejection strategies:

5. Thread pool

6. Custom thread pool

7. Highlights:

4 ways to create a thread *****

Thread synchronization (synchronized, ReentrantLock , ReentrantReadwriteLock )*****

Communication between threads (wait, notify, notifyAll) *****

Common methods of thread class***

Instruction rearrangement, thread contention, visibility, atomicity, volatile keyword

3. Case

1. Two threads take turns printing numbers, from 1-100:

2. Take turns to print 1-52, A-Z, effect 12A....

3. Print two arrays in turn

1. LockSupport tool class

A utility class for thread blocking. All methods are static, allowing the thread to block anywhere
There is also a way to wake up after blocking.
park: stop. (parking)
unpark: start.

Here park and unpark actually implement the functions of wait and notify


the difference:
1.park does not need to acquire a lock on an object
2. Because the interruption of the park will not throw an InstantException exception, you need to judge the interruption status by yourself after the park.
Then do extra processing.

Summarize:
1.park and unpark can implement the functions of wait and notify, but they are not used interchangeably with wait and notify.
2. There is no deadlock in park and unpark.
3. The role of btocker sees the information of the blocking object

 

 public static final Object OBJ=new Object();

    public void show(){
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Runnable runnable=()->{
            synchronized (OBJ){
                System.out.println("thread"+Thread.currentThread().getName()+"]is executing");
                //block
                LockSupport.park("i'm blocked");

                if (Thread.currentThread().isInterrupted()){
                    System.out.println("been interrupted");
                }
                System.out.println("continue");

            }
        };

        Thread t1=new Thread(runnable,"1:");
        Thread t2=new Thread(runnable,"2");
        t1.start();
        Thread.sleep(1000);
        //Get LockSupport.park "I'm blocked" info
        System.out.println(LockSupport.getBlocker(t1));
        t2.start();
        Thread.sleep(3000);
        //thread interruption
        t1.interrupt();
        //wake up t2
        LockSupport.unpark(t2);
        t1.join();
        t2.join();
    }

 

1. Lock

Lock is an interface

keyboard input
printout
Not allowed in development

  public void show(){
        Lock lock=new Lock() {
            @Override
            public void lock() {

            }

            @Override
            public void lockInterruptibly() throws InterruptedException {

            }

            @Override
            public boolean tryLock() {
                return false;
            }

            @Override
            public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
                return false;
            }

            @Override
            public void unlock() {

            }

            @Override
            public Condition newCondition() {
                return null;
            }};
        //lock
        lock.lock();
        try {
            //Handle business logic normally
            //Input and output operations IO operations
            //Operations are physical memory
            //Multithreading is memory processing
        }catch (Exception e){
            //Solutions when exceptions occur
        }finally {//Release resources, close connections, close input and output streams
            //manual release
            lock.unlock();
        }
    }

    public void info() {
        Lock lock = new Lock() {
            @Override
            public void lock() {

            }

            @Override
            public void lockInterruptibly() throws InterruptedException {

            }

            @Override
            public boolean tryLock() {
                return false;
            }

            @Override
            public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
                return false;
            }

            @Override
            public void unlock() {

            }

            @Override
            public Condition newCondition() {
                return null;
            }};
        //If you get the lock
        if (lock.tryLock()){
            try {
                //Handle business logic normally
                //Input and output operations IO operations
                //Operations are physical memory
                //Multithreading is memory processing
            }catch (Exception e){
                //Solutions when exceptions occur
            }finally {//Release resources, close connections, close input and output streams
                //manual release
                lock.unlock();
            }
        }else {
            //
        }
    }

    public static void main(String[] args) {


    }

The implementation class of the Lock interface is ReentrantLockReentrantLock, which is a reentrant lock.
Implements the Lock interface

The difference between synchronized and Lock:
1.Lock is an interface, synchronized is a keyword, which is implemented by the underlying (C) language.
2. When an exception occurs in synchronized, the lock occupied by the thread will be automatically released and no deadlock will occur.
An exception occurs in the Lock. If it is not actively released, it is very likely to occupy resources and not let go. You need to manually release the lock in finally.
3.Lock can make the thread waiting for the lock respond to the interrupt. Using synchronized will only make the waiting thread wait and cannot respond to the interrupt.
4.Lock can improve the efficiency of reading operations by multiple threads.

The following functions of Lock are not available in synchronized!


ReentrantReadwriteLock : For an application, in general, read operations are far more than write operations. If only read operations are not written operations, the data is thread-safe. Read-write locks provide us with a kind of lock, read Many threads can read at the same time, but no thread can write, and the write is exclusive. When a thread is performing the write operation, other threads can neither read nor write.

In some scenarios, the efficiency can be greatly improved!!!

The principle of lock lock cas and aqs


synchronized is implemented by C language and can only be used as a keyword
java provides some concurrent programming packages, the underlying implementation principles cas and aqs


Three characteristics of concurrent programming:
1. Atomicity: Atomic operations can be one step or multiple steps, but the order cannot be chaotic.
Nor can it be cut to perform only a part of it, and the whole operation can be regarded as a whole.
Atomicity is not just multiple lines of code, but possibly multiple instructions.
2. Visibility
3. Orderliness

synchronized lock: can guarantee atomicity, visibility, and ordering.

CAS: compare and swap, compare and swap. JDK11 changed to compare and set.
Idea: When assigning a value to an element, first see if the value in the memory has changed.
AQS: Abstract queue synchronizer, used to solve the problem of thread synchronization execution. it is a doubly linked list

java.util.concurrent.atomic
JUC Concurrent Programming Package


1. Atomic

  • basic type:
  1. AtomicInteger: Integer atomic class
  2. Atomiclong: long integer atomic class
  3. AtomicBoolean: Boolean atomic class
  • Array type:
  1. AtomicLongArray: The original class of long integer arrays
  2. AtomicIntegerArray: Integer array atomic class

2. Thread pool


1. Why use thread pool

(1) Reduce resource consumption. Reduce resource consumption by creating and destroying threads by reusing already created threads
(2) Improve the response speed. When a task arrives, the task can be executed immediately without waiting for the thread to be created.
(3) Mentioned the manageability of the thread. Threads are relatively scarce resources. If they are created without restrictions, they will not only consume system resources, but also
It will also reduce the stability of the system, and the use of thread pools allows for unified allocation, tuning and monitoring.

The four thread pools that come with 7DK are provided by Executors.


1.newCachedThreadPool: Create a cacheable thread pool. If the length of the thread pool exceeds the processing needs, it can flexibly recycle idle threads;
If there is no recycling, create a new thread.
2.newFixedThreadPool: Create a fixed-length thread pool, which can control the maximum number of concurrent threads, and the excess threads will wait in the queue.
3.newScheduledThreadPool: Create a fixed-length thread pool to support timing and periodic task execution
4.newSingLeThreadExecutor: Create a single-threaded thread pool, which will only use a single worker thread to execute tasks, ensuring that
All tasks are executed in the specified order

The initialization of these four thread pools calls the same constructor:
ThreadPooLExecutor(int corePoolSize,
                   int maximumPoolSize,
                   long keepAliveTime,
                   Timeunit unit,
                   BLockingQueue<Runnable> workQueue,
                   ThreadFactory threadFactory,
                   RejectedExecutionHandLer handLer)


2. The meaning of the parameters (important):

  • corePoolSize: the number of threads in the thread pool, the size of the core thread pool
  • maximumPoolSize: specifies the maximum number of threads in the thread pool
  • keepAliveTime: When the number of threads in the thread pool is greater than corePoolSize, how long will the extra idle threads be destroyed unit: time unit
  • workQueue: task queue, used to store submitted but not yet executed tasks
  • threadFactory: thread factory, used to create threads, thread factory is our new thread
  • handLer: Rejection strategy is the corresponding measures taken by the thread pool to reject the task when a task is added to the thread pool.

 

3. Common work queues

  • ArrayBLockingQueue: Array-based bounded blocking queue. FIFO (First In First Out)
  • linkedBLockingQueue: Bounded blocking queue based on linked list. FIFO

 

4. The thread pool provides four rejection strategies:

  • AbortPolicy: Throws an exception directly, the default policy.
  • callerRunPolicy: use the thread where the caller is located to execute the task
  • DiscardOldestPolicy: Discard the top task in the blocking queue and execute the current task DiscardPolicy: Discard any task directly

 

5. Thread pool

  • Create a class that implements the Runnable interface
  • Implement the run() method, and put the code that the thread needs to execute in this method
  • Create a thread pool with a specified number of threads
  • perform thread operations
  • close thread pool

6. Custom thread pool

7. Highlights:

4 ways to create a thread *****

  • The way to inherit the Thread class.
  • The way to implement the Runnable interface.
  • The way to implement the Callable interface.
  • Thread pool based approach

Thread synchronization (synchronized, ReentrantLock , ReentrantReadwriteLock )*****

Communication between threads (wait, notify, notifyAll) *****

wait/notify must be used with synchronized, the wait method releases the lock, and the notify method does not release the lock.

Common methods of thread class***

Instruction rearrangement, thread contention, visibility, atomicity, volatile keyword

3. Case

1. Two threads take turns printing numbers, from 1-100:

 private static class MyNumberTest {

        private static boolean flag = true;

        // number to print
        private static int count = 0;

        public synchronized void print1() {
            for (int i = 0; i < 50; i++) {
                while (!flag) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + "->" + ++count);
                flag = !flag;
                notifyAll();
            }
        }
        public synchronized void print2() {
            for (int i = 0; i < 50; i++) {
                while (flag) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + "->" + ++count);
                flag = !flag;
                notifyAll();
            }
        }

    }

    public static void main(String[] args) {
        MyNumberTest myNumberTest = new MyNumberTest();
        Thread t1 = new Thread(() -> {
            myNumberTest.print1();
        });
        t1.setName("thread A");
        Thread t2 = new Thread(() -> {
            myNumberTest.print2();
        });
        t2.setName("thread B");

        t1.start();
        t2.start();
    }

 

 

2. Take turns to print 1-52, A-Z, effect 12A....

 private static class MyNumberTest {

        private  boolean flag = true;
        private static int count = 1;

        public synchronized void print1() {
            for (int i = 0; i <26; i++) {
                while (!flag) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.print(count);
                System.out.print(++count);
                count++;
                flag = !flag;
                notifyAll();
            }
        }
        public synchronized void print2() {
            for (int i = 65; i < 91; i++) {
                while (flag) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println((char)i);
                flag = !flag;
                notifyAll();
            }
        }

    }

    public static void main(String[] args) {
        Test2.MyNumberTest myNumberTest = new MyNumberTest();
        Thread t1 = new Thread(()->{
            myNumberTest.print1();
        });

        Thread t2 = new Thread(() -> {
            myNumberTest.print2();
        });


        t1.start();
        t2.start();
    }

 

3. Print two arrays in turn

  private static class Test {
        int[]arr1=new int[]{1,2,3,4,5};
        int[]arr2=new int[]{-1,-2,-3,-4,-5};

        private  boolean flag = true;

        public synchronized void print1(int index) {
            for (int i = 0; i <5; i++) {
                while (!flag) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + "--> " + arr1[i]);
                flag = !flag;
                notifyAll();
            }
        }
        public synchronized void print2(int index) {
            for (int i = 0; i < 5; i++) {
                while (flag) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + "--> " + arr2[i]);
                flag = !flag;
                notifyAll();
            }
        }

    }

    public static void main(String[] args) {
        Test3.Test test = new Test3.Test();
        Thread t1 = new Thread(()->{
            test.print1(0);
        });
        t1.setName("Array one:");

        Thread t2 = new Thread(() -> {
            test.print2(0);
        });
        t2.setName("Array two:");


        t1.start();
        t2.start();
    }

 

Tags: Java Multithreading

Posted by Traduim on Thu, 22 Sep 2022 22:36:15 +0530