Java learning notes -- Java language foundation (inter thread communication, thread pool, Timer class)

Posted by forcerecon on Thu, 05 Mar 2020 08:46:57 +0100

1, Communication between threads

When multiple threads use one resource, the tasks of each thread are different. This is the problem of communication between threads.
Why do I deal with inter thread communication?
When multiple threads execute at the same time, the CPU switches threads randomly by default. When we need multiple threads to complete a task together, and we want them to execute regularly, then we need some coordination and communication between multiple threads to help us achieve a common operation of data by multiple threads.
Ensuring the effective utilization of resources in inter thread communication -- waiting for wakeup mechanism
When multiple threads are processing the same resource and tasks are different, they need thread communication to help solve the use or operation of the same variable between threads. When multiple threads operate on the same data, they can avoid competing for the same shared variable
After a thread has performed the specified operation, it will enter the wait state (wait()), wait for other threads to execute their specified code and wake it up (notify()); when there are multiple threads waiting, if necessary, you can use notifyAll() to wake up all waiting threads.
The wake-up waiting mechanism is used to solve the problem of inter thread communication. Three methods are used:

1. wait: the thread is no longer active, no longer participates in scheduling, and enters the wait set, so it will not waste CPU resources, and will not compete for locks. At this time, the thread state is WAITING. It also waits for another thread to perform a special action, that is, "notify" the thread WAITING on this object to be released from the wait set and re entered into the ready queue
 2. notify: select a thread in the wait set of the notified object to release;
3. notifyAll: release all threads on the wait set of the notified object.

Details of calling wait and notify methods

1. The wait method and the notify method must be called by the same lock object. Because: the corresponding lock object can wake up the thread after the wait method called by the same lock object through notify.
2. wait method and notify method belong to the method of Object class. Because: lock Object can be any Object, and the class of any Object is inherited from the Object class.
3. wait method and notify method must be used in synchronization code block or synchronization function. Because: these two methods must be called through the lock object.

Code implementation:
Define a package subclass: set the properties of a package

public class Baozi {
    String pi;
    String xian;
    //Set initial value status
    boolean flag=false;
}

Define a baozi eating class:

public class ChiHuo extends Thread{
    private Baozi baozi;
    // 2. Use the construction method to assign values to the package variables
    public ChiHuo(Baozi baozi) {
        this.baozi = baozi;
    }

    @Override
    public void run() {
        while (true){
            synchronized (baozi){
                if (baozi.flag==false){
                    try {
                        baozi.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //After the thread is awakened
                System.out.println("Eating steamed buns"+baozi.pi+baozi.xian);

               baozi.flag=false;
               //Wake up the thread of baozi shop
               baozi.notify();
                System.out.println("Already put"+baozi.pi+baozi.xian+"I'm full,Baozipu continues to produce baozi");
                System.out.println("=============");
            }
        }
    }
}

Define the class of the package shop:

public class BaoZiPu extends Thread{
    //1. Create package sub variable
    private Baozi baozi;
    // 2. Use the construction method to assign values to the package variables
    public BaoZiPu(Baozi baozi) {
        this.baozi = baozi;
    }

    @Override
    public void run() {
        //Define a variable
        int conut=0;
        while (true){
            synchronized (baozi){
                if (baozi.flag==true){
                    try {
                        baozi.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //After being woken up, Baozi shop produces baozi
                if (conut%2==0){
                    //Produce a kind of steamed bun
                    baozi.pi="Thin skin";
                    baozi.xian="three delicacies";
                }else {
                    baozi.pi="Ice skin";
                    baozi.xian="beef";
                }
                conut++;
                System.out.println("Baozipu is in production"+baozi.pi+baozi.xian);
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                baozi.flag=true;
                //Wake up the baozi eating thread
                baozi.notify();
                System.out.println("Finished production"+baozi.pi+baozi.xian);
            }
        }

    }
}

Test class:

public class Test {
    public static void main(String[] args) {
        Baozi baozi = new Baozi();
        new BaoZiPu(baozi).start();
        new ChiHuo(baozi).start();
    }
}

2, Thread pool

When we use threads, we create a thread, which is very easy to implement. If there are many concurrent threads, and each thread executes a task with a short time, it will end, so frequent creation of threads will greatly reduce the efficiency of the system, because frequent creation and destruction of threads take time.
This is that we can use thread pool to meet our needs

2.1 concept of thread pool

Thread pool: in fact, it is a container that holds multiple threads. The threads in the pool can be used repeatedly, eliminating the operation of frequently creating thread objects, and consuming too much resources without repeatedly creating threads.
Benefits of using thread pools:

1. Reduce resource consumption. It reduces the number of threads created and destroyed, and each worker thread can be reused to perform multiple tasks.
2. Improve the response speed. When the task arrives, the task can be executed immediately after the thread is created.
3. Improve the manageability of threads. You can adjust the number of work line threads in the thread pool according to the system's tolerance to prevent the server from getting tired of consuming too much memory (each thread needs about 1MB of memory, and the more threads are opened, the more memory is consumed, and finally crashes).

Creation of thread pool:

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) 
          Create a new ThreadPoolExecutor with the given initial parameters and the default thread factory and the rejected execution handler.

Parameter introduction:

corePoolSize: number of core threads in thread pool
 maximumPoolSize: maximum number of threads in the thread pool
 keepAliverTime: when the number of active threads is greater than the number of core threads, the maximum survival time of idle redundant threads
 Unit: unit of survival time
 workQueue: the queue in which tasks are stored
 Handler: handler for tasks beyond thread scope and queue capacity

Implementation principle of thread pool:

1. Determine whether all the core threads in the thread pool are executing tasks. If not, create a new worker thread to execute tasks. If the core threads are all executing tasks, the next process is started.
2. The thread pool determines whether the work queue is full. If the work queue is not full, the newly submitted tasks will be stored in the work queue. If the work queue is full, go to the next process.
3. Determine whether all threads in the thread pool are in working state. If not, create a new worker thread to execute the task. If it's full, it's up to the saturation strategy to handle the task.

JDK5 adds an Executors factory class to generate thread pool, ExecutorService thread pool
Construction method:

public static ExecutorService newCachedThreadPool(): create the number of threads corresponding to the thread according to the number of tasks	
public static ExecutorService newFixedThreadPool(int nThreads): initializes several threads
 public static ExecutorService newSingleThreadExecutor(): initializes the thread pool of a thread

The return value of these methods is ExecutorService object, which represents a thread pool and can execute the thread represented by Runnable object or Callable object.

public class MyTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //Create a thread pool to create the corresponding number of threads according to the number of tasks
        ExecutorService executorService = Executors.newCachedThreadPool();
        //Submit Runnable task to thread pool submit 3 tasks will create 3 threads
        MyRunnable myRunnable = new MyRunnable();
        executorService.submit(myRunnable);
        executorService.submit(new MyRunnable());
        executorService.submit(new MyRunnable());
        //
        Future<?> future = executorService.submit(new MyCallable(100));
        //Can get the return value
        Integer o = (Integer) future.get();
        //Sum of output 1-100
        System.out.println(o);//5050

        Future<Integer> submit = executorService.submit(new MyCallable(10));
        Integer integer = submit.get();
        System.out.println(integer);
        //Close thread pool
        executorService.shutdown();
    }
}

class MyCallable implements Callable<Integer> {
    int num;
    public MyCallable(int num) {
        this.num=num;
    }

    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName() + "Callable Task performed");
        int sum=0;
        for (int i = 0; i <= num; i++) {
            sum+=i;
        }
        return sum;
    }
}

class MyRunnable implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "Runnable Task performed");
    }
}

Execution result:

As can be seen from the results, the thread pool creates three threads. When a thread finishes executing a Runnable task, the thread can perform other tasks.
Use newfixedthreadpool (int nthreads): number of threads in the fixed thread pool.

public class MyTest2 {
    public static void main(String[] args) {
       // Public static executorservice newfixedthreadpool (int nthreads): initializes several threads
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        //Submit tasks to thread pool
        executorService.submit(new IRunnable());
        executorService.submit(new IRunnable());
        executorService.submit(new IRunnable());
        executorService.submit(new IRunnable());
        executorService.submit(new IRunnable());
        executorService.submit(new IRunnable());
        //Close thread pool
        executorService.shutdown();
    }
}

class IRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"Perform tasks");
    }
}


The number of fixed threads is 2. When a task needs to be executed, a thread will be provided to execute the task. Other tasks are waiting. When the task is finished, the thread will execute the next task.

3, Timer class

A tool used by a thread to schedule tasks to be performed later in a background thread. You can schedule tasks to be performed once, or repeatedly on a regular basis.

Timer is a widely used thread tool, which can be used to schedule multiple scheduled tasks to be executed by subsequent threads. In Java, the function of defining schedule can be realized through timer and TimerTask classes.
Construction method:

Timer() creates a new timer.
Timer(String name) creates a new timer whose associated thread has the specified name.

Timer method:

schedule(TimerTask task, Date time) schedules the execution of the specified task at the specified time.
schedule(TimerTask task, Date firstTime, long period) schedules the specified task to start repeated fixed delay execution at the specified time.
schedule(TimerTask task, long delay) schedules the execution of the specified task after the specified delay.

TimerTask: a task scheduled by Timer to be executed once or repeatedly.
Methods

cancel() cancels this timer task.
 run() the action to be performed by this timer task.

Use 1: use the construction method schedule(TimerTask task, long delay) to schedule to execute the specified task after the specified delay.

public class MyTimerDemo {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("Enter the time of the explosion");
        int i = sc.nextInt();
        int time=i*1000;
        //Construct a timer
        Timer timer = new Timer();
        System.out.println("Tips"+i+"It will explode in seconds");
        //Parameter 1: task parameter 2: waiting time
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("Bang~blast");
            }
        },time);
        timer.cancel();
    }
}

Use 2: cancel timer task after timer execution
The task needs to be closed after the execution of the run method of TimerTask

public class MyTimerDemo2 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("Enter the time of the explosion");
        int i = sc.nextInt();
        int time=i*1000;
        System.out.println("Tips"+i+"It will explode in seconds");
        Timer timer = new Timer();
        timer.schedule(new MyTimerTask(timer),time);
    }
}
class MyTimerTask extends TimerTask{
    Timer timer;
    //Parameter passing timer can cancel timer
    public MyTimerTask(Timer timer) {
        this.timer=timer;
    }
    @Override
    public void run() {
        System.out.println("Bang~blast");
        timer.cancel();
    }
}

Use 3: use the construction method schedule(TimerTask task, Date time) to schedule the execution of the specified task at the specified time.
Delete folder regularly

public class MyTimerDemo3 {
    public static void main(String[] args) throws ParseException {
        Timer timer = new Timer();
        String str = "2020-02-19 15:23:00";
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = simpleDateFormat.parse(str);
        timer.schedule(new MyTimerTask2(timer), date);

    }
}

class MyTimerTask2 extends TimerTask {
    Timer timer;

    //Parameter passing timer can cancel timer
    public MyTimerTask2(Timer timer) {
        this.timer = timer;
    }

    @Override
    public void run() {
        File file = new File("C:\\Users\\asus\\Desktop\\24.[Stream Flow, method reference");
        deleteFloder(file);
        timer.cancel();
    }

    private void deleteFloder(File fileFloder) {
        File[] files = fileFloder.listFiles();
        for (File file : files) {
            if (file.isFile()) {
                file.delete();
            }else {
                deleteFloder(file);
            }
        }
        fileFloder.delete();
    }
}
Published 27 original articles, won praise 5, visited 674
Private letter follow

Topics: Java