Tag Archives: java

Three ways of thread sequence alternate execution in Java lock free programming

1. Principle analysis

Atomicinteger is thread safe, and autoincrement is thread safe.

2. Code examples

package com.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class TasksTest extends Thread {
    private static AtomicInteger atomic = new AtomicInteger(1);
    private int id;

    public TasksTest(int id) {
        this.id = id;
    }

    @Override
    public void run() {
        while (atomic.get() <= 12) {
            while (atomic.get() % 3 == id) {
                System.out.println("thread_" + id + " output:" + atomic.get());
                atomic.incrementAndGet();
            }
        }
    }

    public static void main(String[] args) {
        Thread thread0 = new TasksTest(0);
        Thread thread1 = new TasksTest(1);
        Thread thread2 = new TasksTest(2);

        ExecutorService exec = Executors.newFixedThreadPool(3);

        exec.submit(thread0);
        exec.submit(thread1);
        exec.submit(thread2);

        exec.shutdown();

    }
}

Implementation of retrial mechanism in Java

Keywords: thread, thread pool, queue, task scheduling

1. Retrying tool class

package com.iretry;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * Retry Tools Class
 */
@Slf4j
public class RetryUtils {

    private final static int DEFAULT_RETRY_TIMES = 6;
    private final static int[] DEFAULT_DELAY_SECONDS = {3, 30, 180, 600, 1800, 3600};

    private static Queue<RetryRunnable> TASK_QUEUE = new ConcurrentLinkedQueue<>();

    public static ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    public static ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();

    static {
        //Configure the number of core threads
        executor.setCorePoolSize(10);
        // Configure the maximum number of threads
        executor.setMaxPoolSize(20);
        //configure queue size
        executor.setQueueCapacity(1000);
        //configure the name prefix of the threads in the thread pool
        executor.setThreadNamePrefix("async_");
        // rejection-policy: how to handle new tasks when the pool has reached max size
        // CALLER_RUNS: instead of executing the task in a new thread, the caller's thread will execute it
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //Perform initialization
        executor.initialize();

        scheduler.setThreadNamePrefix("scheduler_");
        scheduler.setPoolSize(5);
        scheduler.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        scheduler.initialize();
    }

    public RetryUtils() {
        //Check every second: iterate through the task queue, if needed, the thread pool schedules execution
        scheduler.scheduleAtFixedRate(() -> {
            for (RetryRunnable task : TASK_QUEUE) {
                long nextRetryMillis = task.nextRetryMillis;
                if (nextRetryMillis != -1 && nextRetryMillis <= System.currentTimeMillis()) {
                    task.nextRetryMillis = -1;
                    executor.execute(task);
                }
            }
        }, 1000);
    }

    public void doRetry(Task task) {
        doRetry(DEFAULT_RETRY_TIMES, DEFAULT_DELAY_SECONDS, task);
    }

    public void doRetry(int maxRetryTime, Task task) {
        doRetry(maxRetryTime, DEFAULT_DELAY_SECONDS, task);
    }

    public void doRetry(int[] retryDelaySeconds, Task task) {
        doRetry(retryDelaySeconds.length, retryDelaySeconds, task);
    }

    /**
     * @param maxRetryTime      Maximum number of retries
     * @param retryDelaySeconds array of retry interval times
     * @param task task
     */
    public void doRetry(final int maxRetryTime, final int[] retryDelaySeconds, final Task task) {
        Runnable runnable = new RetryRunnable(maxRetryTime, retryDelaySeconds, task);
        executor.execute(runnable);
    }

    /**
     * Custom Threads Class
     */
    private static class RetryRunnable implements Runnable {

        private final Task task;
        private final int maxRetryTimes;
        private final int[] retryDelaySeconds;

        private int retryTimes;
        private volatile long nextRetryMillis;

        //Constructors
        public RetryRunnable(final int maxRetryTimes, final int[] retryDelaySeconds, final Task task) {
            this.task = task;
            if (maxRetryTimes <= 0) {
                this.maxRetryTimes = DEFAULT_RETRY_TIMES;
            } else {
                this.maxRetryTimes = maxRetryTimes;
            }
            if (retryDelaySeconds == null || retryDelaySeconds.length == 0) {
                this.retryDelaySeconds = DEFAULT_DELAY_SECONDS;
            } else {
                this.retryDelaySeconds = retryDelaySeconds;
            }
        }

        //Implementation of business methods
        @Override
        public void run() {
            try {

                task.run();

            } catch (Throwable e) {
                int sleepSeconds = retryTimes < retryDelaySeconds.length ?retryDelaySeconds[retryTimes] : retryDelaySeconds[retryDelaySeconds.length - 1];

                if (retryTimes < maxRetryTimes) {
                    if (retryTimes == 0) {
                        TASK_QUEUE.add(this);
                        log.error("task executed error, " + sleepSeconds + " seconds do next... ", e);
                    } else {
                        log.error("retry " + retryTimes + " times error, " + sleepSeconds + " seconds do next... ", e);
                    }
                    nextRetryMillis = System.currentTimeMillis() + sleepSeconds * 1000;

                } else {
                    log.error("retry " + retryTimes + " times error", e);
                    log.error("retry snapshot: {}", JSON.toJSONStringWithDateFormat(task.snapshot(), "yyyy-MM-dd HH:mm:ss"));

                    TASK_QUEUE.remove(this);
                    task.retryFailed(e);

                }

                retryTimes++;

            }
        }
    }

}

2. Business class interface

package com.iretry;

public interface Task {

    void run() throws Exception;

    default void retryFailed(Throwable e) {
    }

    default Object snapshot() {
        return null;
    }
}

3. Test class

package com.iretry;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

import java.util.concurrent.ThreadPoolExecutor;

@Slf4j
public class IRetryTest {

    public static void main(String[] args) {
        RetryUtils retryUtils = new RetryUtils();

        IRetryTest iRetryTest = new IRetryTest();
        iRetryTest.executeBusiness(retryUtils, new IRetryTest().new UserInfo("Jack"));

    }

    //Business methods that require retries
    private void executeBusiness(RetryUtils retryUtils, UserInfo user) {

        retryUtils.doRetry(new int[]{6, 12}, new Task() {
            @Override
            public void run() throws Exception {
                user.setName("Henry");
                log.info("Execute the operation, change the name of the employee to: " + user.getName());
                Integer a = 1/0;

            }

            // Support rollback operations after final failure
            @Override
            public void retryFailed(Throwable e) {
                user.setName("Jack");
                log.info("Retry failed, business data rolled back...") ;
                log.info("Username is called." + user.getName());
            }

            @Override
            public Object snapshot() {
                return user;
            }
        });
    }


    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    private class UserInfo {
        private String name;
    }


}

4. Implementation results

Code case of XXL job executor

1. POM is introduced. Note: the version number should be consistent with XXL job admin.

       <dependency>
            <groupId>com.xuxueli</groupId>
            <artifactId>xxl-job-core</artifactId>
            <version>1.9.2-SNAPSHOT</version>
        </dependency>

2、application.yml

xxl:
  job:
    admin:
      addresses: http://47.102.168.36:9500
    executor:
      log-path: ${catalina.home:/usr}/logs/job
      log-retention-days: 30
      ip: 127.0.0.1
      port: 10001

3. Configure executor bean

import com.xxl.job.core.executor.XxlJobExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


/**
 * xxl-job config
 */
@Configuration
public class XxlJobConfig {
    private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);

    @Value("${xxl.job.admin.addresses}")
    private String adminAddresses;

    @Value("${spring.application.name}")
    private String appName;

    @Value("${xxl.job.executor.ip}")
    private String ip;

    @Value("${xxl.job.executor.port}")
    private Integer port;

    @Value("${xxl.job.executor.log-path}")
    private String logPath;

    @Value("${xxl.job.executor.log-retention-days}")
    private int logRetentionDays;


    @Bean(initMethod = "start", destroyMethod = "destroy")
    public XxlJobExecutor xxlJobExecutor() {
        logger.info(">>>>>>>>>>> xxl-job config init.");
        XxlJobExecutor xxlJobExecutor = new XxlJobExecutor();
        xxlJobExecutor.setAdminAddresses(adminAddresses);
        xxlJobExecutor.setAppName(appName);
        xxlJobExecutor.setIp(ip);
        xxlJobExecutor.setPort(port);
        xxlJobExecutor.setPort(-1);
        xxlJobExecutor.setAccessToken(null);
        xxlJobExecutor.setLogPath(logPath);
        xxlJobExecutor.setLogRetentionDays(logRetentionDays);
        return xxlJobExecutor;
    }
}

4. Task code

import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.handler.annotation.JobHandler;
import com.xxl.job.core.log.XxlJobLogger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * JOB
 */
@JobHandler(value = "iFlyTenantJob")
@Component
public class IFlyTenantJob extends IJobHandler {

    private static final Logger log = LoggerFactory.getLogger(IFlyTenantJob.class);

    @Override
    public ReturnT<String> execute(String s) {
        XxlJobLogger.log("The mission begins...") ;
        log.info("Task started...");

        iFlyAiService.queryTenants();
        try {
            Thread.sleep(6000);
            //int a = 1/0;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        XxlJobLogger.log("End of mission...");
        log.info("End of mission...");
        return ReturnT.SUCCESS;

    }


}

Asynchronous processing of HTTP request by Java_ Method 1: through callable

1.Callable

1) Runnable, which performs an independent task but does not return a value. If you want a return value after the task is completed, you can use the callable interface;

2) Callable is a paradigm with type parameters. Its type parameter method is expressed as the value returned by the method call () instead of run (), and it must be used ExecutorService.submint () method.

difference:

1. Callable, which accepts a generic type and returns a value of this type in the call() method; however, runnable’s run() method has no return value;
2. Callable, whose call() method can throw an exception, while runnable’s run() method does not.

2. Business scenario:

In HTTP requests, the business processing process takes a long time, such as large queries, remote calls and other scenarios. The main thread that receives HTTP requests will be occupied all the time, and the number of threads in Tomcat thread pool is limited. Therefore, the number of HTTP requests accepted per unit time will decrease.

3. Code examples

1)controller

package com.liuxd.controller;

import com.liuxd.entity.Responses;
import com.liuxd.service.BusinessService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.Callable;

@Slf4j
@RestController
public class AsyncCallableController {

    @Autowired
    private BusinessService businessService;

    @GetMapping(value = "/getData")
    public Callable<Responses<String>> getData() {

        log.info("HTTP request received...");

        Callable<Responses<String>> data = (() -> {
            return businessService.getData();
        });

        log.info("The task of the receiving HTTP request thread has been completed, exit!");

        return data;
    }

}

2) service

package com.liuxd.service;

import com.liuxd.entity.Responses;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class BusinessService {

    public Responses<String> getData(){

        log.info("Call the service method and start the execution...");

        try {
            Thread.sleep(2500L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        log.info("Call service method, end of execution!");

        return new Responses<>(0,"Done","SUCCESS");

    }

}

3) Print results

Asynchronous callback case of Java callback function

1. Callback function classification

Callback function distinction: synchronous callback and asynchronous callback

Synchronous callback: the meaning is only to complete the method call;

Asynchronous call: concurrency can be realized, and the main business thread can be released in time; asynchronous thread completes the work, executes callback function, and completes the aftermath work; the execution efficiency is improved.

2. Code examples

1. Note testing

package com.callback2;

public class AsyncCallBack {

    public static void main(String[] args) {
        System.out.println("Start of the main business thread ID:" + Thread.currentThread().getId());
        System.out.println("------------------");

        Son son = new Son();
        Mother mother = new Mother(son);

        mother.notice();
        son.writeHomeWork();

        System.out.println("End of the main business thread ID:" + Thread.currentThread().getId()+"\n");

    }

}

2. Mother

package com.callback2;

public class Mother {
    private Son son;
    public Mother(Son son) {
        this.son = son;
    }

    public void notice() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Notify the mother of the thread ID." + Thread.currentThread().getId());
                cookFood("Bread");
            }
        }).start();
    }

    public void cookFood(String bread) {
        System.out.println("Current cooking thread ID." + Thread.currentThread().getId());
        try {
            System.out.println("Mother Baking" + bread + "...");
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Mother has baked the bread");
        String message = "Ming, come and eat!";

        son.callback(message);

    }

}

3. My son Xiao Ming

package com.callback2;

public class Son {
    private String status = "";

    public void writeHomeWork() {
        System.out.println("Xiaoming writing homework thread ID: " + Thread.currentThread().getId());
        System.err.println("Ming is writing his homework...") ;
        setStatus("Writing homework");
    }


    public void callback(String message) {
        System.out.println("Callback Xiaoming meal thread ID: " + Thread.currentThread().getId());
        System.err.println(message);
        System.err.println("Okay, coming right up!") ;
        System.out.println("Ming started eating!") ;
        setStatus("Eating in progress");
        System.out.println("Xiaoming executing meal thread ID." + Thread.currentThread().getId());
    }

    public String getStatus() {
        return status;
    }
    public void setStatus(String status) {
        this.status = status;
    }
}

4. Implementation results

Business Main Thread Start ID: 1
------------------
Xiaoming writing homework thread ID: 1
Xiaoming writing homework in progress...
Business main thread end ID:1

Notify mother thread ID:12
Currently cooking thread ID:12
Mother baking bread...
Mother baked the bread
Callback to Xiaoming to eat Thread ID: 12
Ming, come and eat!
Okay, coming right up!
Ming starts eating!
Xiaoming executes meal thread ID: 12

5. Result analysis

1) Xiao Ming uses the main thread to do his homework (if he can’t finish it, he doesn’t need to care);

2) Mother uses the new thread to cook [concurrent], mother finishes the meal, executes the callback function, and notifies Xiao Ming to eat;

3) Xiao Ming uses a new thread and starts to eat.

Java callback function implementation case

1. What is a callback function

Callback function is a function called by function pointer. If you pass a function pointer (address) as a parameter to another function, when the pointer is used to call the function it points to, we say it is a callback function. In Java, pointers are called references. </ u> the callback function is not called directly by the implementer of the function, but by another party when a specific event or condition occurs, which is used to respond to the event or condition.

A callback method is any method that is called by another method with the callback method as its first parameter. Many times, a callback is a method that is called when something happens.

2. Application scenarios

Event driven mechanism

For example: Party A hires Party B to repair the car; then Party A goes to do other things; Party B notifies Party A that the car has been repaired, please come and get it. There is no need for Party A to wait for Party B to finish repairing the car.

3. Code examples

1. Test class

package com.callBack;
public class CallBckTest {

    public static void main(String[] args) {
        MainBusiness mainBusiness = new MainBusiness();

        System.out.println("*********The specific implementation class implements the callback method *********");
        mainBusiness.execute(new CallbackServiceImpl());

        System.out.println("********* anonymous internal class implements the callback method ********* flexible *********");
        mainBusiness.execute(new CallbackService() {
            public void callBackFunc() {
                System.out.println("The anonymous internal class callback function started executing...") ;
                System.out.println("Anonymous internal class callback function ends execution...\n");
            }
        });
    }
}

2. Business class and method

package com.callBack;
public class MainBusiness {

    private CallbackService callback;

    public void execute(CallbackService callback) {
        this.callback = callback;
        callBack();
    }

    public void callBack() {
        callback.callBackFunc();
    }
}

3. Callback function interface

package com.callBack;
//Callback functions of the interface and methods
public interface CallbackService {
    void callBackFunc();
}

4. Callback function implementation class

package com.callBack;
public class CallbackServiceImpl implements CallbackService {
    @Override
    public void callBackFunc() {
        System.out.println("The concrete implementation class callback function starts execution...") ;
        System.out.println("Concrete implementation class callback function ends execution...\n");
    }
}

5. Print results

*********Concrete implementation class implements the callback method *********
Concrete implementation class callback function starts execution...
Concrete implementation class callback function ends execution...

********* callback methods implemented by anonymous internal classes *********
Anonymous internal class callback function start execution...
Anonymous internal class callback function ends execution...

Could not create connection to database server. Attempted reconnect 3 times. Giving

1. Questions

The program connection to the database is abnormal, as follows:

Could not create connection to database server. Attempted reconnect 3 times. Giving 

2. Solutions

I tried a variety of solutions, and finally realized: MySQL connector- java.jar Inconsistent with the latest database version. The database is the latest version of 8

0.19,mysql-connector- java.jar It’s 5.0.6.

Solution: MySQL connector- java.jar Keep the same version number as the database.

The POM file is as follows, please check and modify the version by yourself; some versions are compatible, but it is better to keep them unified.

<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>8.0.19</version>
</dependency>

 

Why must microservices have gateways?

1、 What is a service gateway

Service gateway = route forwarding + filter

1. Route forwarding: receive all external requests and forward them to the back-end micro service.

2. Filter: in the service gateway, a series of crosscutting functions can be completed, such as permission verification, current limiting and monitoring. All these can be completed through the filter (in fact, routing and forwarding are also realized through the filter).

2、 Why a service gateway is needed
the above crosscutting function (taking permission verification as an example) can be written in three places:

1) each service is implemented by itself [not recommended]

2) write to a public service, and then all other services depend on this service [not recommended]

3) write it to the prefilter of the service gateway, and all requests come to check the permission [recommended]

First, the disadvantages are too obvious to use;
Second, compared with the first point, the code development is not redundant, but there are two disadvantages:

(1) because each service introduces this public service, it is equivalent to introducing the same permission verification code in each service, which increases the jar package size of each service for no reason. Especially for the deployment scenario using docker image, the smaller the jar, the better;

       ② Since this public service is introduced into every service, it may be difficult for us to upgrade this service in the future. Moreover, the more functions the public service has, the more difficult it will be to upgrade. Suppose we change the way of permission verification in public service. If we want all services to use the new way of permission verification, we need to re package all previous services , compile the deployment.

The service gateway can solve this problem

    write the logic of permission verification in the filter of the gateway, the back-end service does not need to pay attention to the code of permission verification, so the logic of permission verification will not be introduced into the jar package of the service, and the size of the jar package will not be increased; if you want to modify the logic of permission verification, you only need to modify the filter of permission verification in the gateway, without upgrading all existing micro services.

So, need service gateway!!!

 

3、 Service gateway technology selection

 

After the introduction of service gateway, the microservice architecture is as above, including three parts: service gateway, open service and service.

1. Overall process:

The service gateway, open service and service are registered in the registry when they are started; the user requests the gateway directly, and the gateway performs intelligent routing and forwarding (including service discovery and load balancing) to the open service, which includes permission verification, monitoring, current limiting and other operations. The open service aggregates the internal service response, returns it to the gateway, and the gateway returns it to the user

2. Points for attention in introducing gateway

With the addition of gateway and one more layer of forwarding (originally, the user requested to directly access the open service), the performance will decline (but the decline is not big. Generally, the performance of gateway machine will be very good, and the access between gateway and open service is usually intranet access, which is very fast); single point problem of gateway: there must be a single point in the whole network call process, which may be Gateway, nginx, DNS server, etc. To prevent gateway single point, you can hang another nginx in front of the gateway layer. The performance of nginx is very high, and it will not hang basically. After that, the gateway service can continuously add machines. However, such a request is forwarded twice, so the best way is to deploy the gateway single point service on a powerful machine (estimate the configuration of the machine through pressure test). Moreover, the performance comparison between nginx and zuul is similar according to the experiment done by a foreign friend. Zuul is an open source framework for gateway of Netflix, and the gateway should be fully implemented Light weight.

3. Basic functions of service gateway

Intelligent routing: receive all external requests and forward them to the external service open service of the back end;

Note: we only forward external requests, and requests between services do not go through the gateway. This means that full link tracking, internal service API monitoring, fault tolerance of calls between internal services, and intelligent routing cannot be completed in the gateway. Of course, all service calls can go through the gateway, and almost all functions can be integrated into the gateway, but in this case, the gateway’s pressure can be reduced It’s going to be very heavy. Permission verification: only the user’s request to the open service is verified, and the internal request of the service is not verified. Is it necessary to verify the request inside the service?API monitoring: only monitor the requests passing through the gateway and some performance indicators of the gateway itself (for example, GC, etc.); current limiting: cooperate with the monitoring to carry out current limiting operation; API log unified collection: similar to an aspect aspect aspect, record the relevant log when the interface enters and goes out… Follow up supplement

The above functions are the basic functions of the gateway, and the gateway can also realize the following functions:

A | B test: a | B test is a relatively large thing, including background experiment configuration, data burial point (see conversion rate) and streaming engine. In the service gateway, the streaming engine can be realized, but in fact the streaming engine will call internal services, so if it is in accordance with the architecture in the figure above, the streaming engine should be in the open service rather than in the service gateway…. Follow up supplement

 

4. Technology selection

The author is going to build a lightweight service gateway

Development language: java + groovy, the advantage of groovy is that the gateway service can dynamically add filter to achieve some functions without restart; microservice basic framework: springboot; gateway basic component: Netflix zuul; service registry: consult; permission verification: JWT; API monitoring: Prometheus + grafana; API unified log collection: logback+ Elk; stress test: JMeter;… Follow up supplement

In the follow-up introduction, will gradually introduce each knowledge point, and complete a lightweight service gateway!!!

Java uses lock to realize multithread sequential alternate execution mode 2

1. Principle

Lock synchronization lock

Signal() and await() of condition

2. Code examples

package com.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TasksTestLock extends Thread {
    private static Lock lock = new ReentrantLock();
    private static Condition condition = lock.newCondition();
    private static int num = 1;
    private int id;

    public TasksTestLock(int id) {
        this.id = id;
    }


    @Override
    public void run() {
        while (num <= 12) {

            lock.lock();

            System.out.println("Thread" + id + " num:" + num);
            num++;

            condition.signal();
            try {
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            lock.unlock();

        }
    }


    public static void main(String[] args) {
        Thread thread0 = new TasksTestLock(0);
        Thread thread1 = new TasksTestLock(1);

        ExecutorService exec = Executors.newFixedThreadPool(3);

        exec.submit(thread0);
        exec.submit(thread1);

        exec.shutdown();

    }
}

3. Output results

 

Implementation of multithread sequential alternate execution by using lock in Java

1. Principle

Synchronized thread synchronization

Notify() calls up the thread

The wait() thread waits

2. Code examples

package com.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TasksTestSync extends Thread {
    private static Integer num = 0;
    private int id;

    public TasksTestSync(int id) {
        this.id = id;
    }

    @Override
    public void run() {
        while (num < 12) {
            synchronized (TasksTestSync.class) {
                num = num + 1;
                System.out.println("thread_" + id + " num:" + num);

                TasksTestSync.class.notify();
                try {
                    TasksTestSync.class.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }
    }

    public static void main(String[] args) {
        Thread thread0 = new TasksTestSync(0);
        Thread thread1 = new TasksTestSync(1);

        ExecutorService exec = Executors.newFixedThreadPool(3);

        exec.submit(thread0);
        exec.submit(thread1);

        exec.shutdown();

    }
}

3. Implementation results

Why use thread pools? Remember and understand

1. Reduce cost and improve efficiency

Reduce the time of thread creation and destruction and the overhead of system resources;

At the same time, it improves the response speed of the system. When a new task arrives, it can be executed immediately by reusing the existing thread without waiting for the creation of a new thread.

2. Improve the manageability of threads

It is convenient to control the number of concurrent threads. Unlimited thread creation may lead to excessive memory consumption, resulting in oom, and will cause excessive CPU switching. There is a time cost for CPU switching threads: it is necessary to keep the scene of the current thread and restore the scene of the thread to be executed.

It can allocate, tune and monitor threads in a unified way, so as to improve the response speed, and provide more powerful functions, such as delaying and timing thread pool.