Java Multithreading optimization and usage

Source: Internet
Author: User
Tags thread class

First, Multithreading introduction

In programming, we can run into multi-threaded programming problems because of the need for concurrent processing in most business systems, and multithreading is important in concurrent scenarios. Also, when we interview, interviewers often ask us questions about multithreading, such as: How to create a thread? We usually answer this, there are two main methods, the first one: Inherit the thread class, rewrite the Run method, and the second: Implement the Runnable interface, overriding the Run method. Then the interviewer will certainly ask the pros and cons of both approaches, however, we will come to the conclusion that using mode two, because object-oriented advocates less inheritance, as many combinations as possible.

This time, we may also think, if you want to get multi-threaded return value what to do? Based on the knowledge we have learned, we will think of implementing the callable interface and overriding the call method. How many threads do they use in the actual project?

First, let's look at an example:

This is a simple way to create multithreading, it is easy to understand, in the example, according to different business scenarios, we can pass in the thread () in the different parameters to implement different business logic, but this method to create multi-threaded burst out of the problem is to create threads repeatedly, and after the creation of the thread has to be destroyed, This may seem possible if the concurrency scenario is low-demand, but in high concurrency scenarios, this is not the case because creating threads to destroy threads is very resource-intensive. So, based on experience, the correct approach is that we use thread pooling technology, and the JDK provides a variety of thread pool types that we can choose from, in particular, to consult the documentation for the JDK.

Here the code we need to note is that the incoming parameter represents the number of threads we configure, is not the more the better? Definitely not. Because we configure the number of threads to fully consider the performance of the server, the number of threads configured, the performance of the server may not be excellent. In general, machine-completed calculations are determined by the number of threads, and when the number of threads reaches a peak, it cannot be calculated. If the CPU-consuming business logic (more compute), the number of threads and the same number of cores to reach the peak, if the consumption of I/O business logic (Operation database, file upload, download, etc.), the more the number of threads in a sense to help improve performance.

The size of the number of threads is set another formula determines:

y=n* (A+B)/a), wherein, n:cpu the number of cores, a: The calculation time of the program when the thread executes, B: When the thread executes, the program's blocking time. With this formula, the number of threads in the thread pool is configured to be constrained, and we can configure it flexibly according to the actual situation of the machine.

Second, multithreading optimization and performance comparison

Recent projects have used the threading technology, in the use of the process encountered a lot of trouble, take advantage of the heat, sorting out several multi-threaded framework performance comparison. Currently mastered by roughly three kinds, the first kind: ThreadPool (thread pool) +countdownlatch (program counter), the second: Fork/join framework, the third JDK8 parallel stream, the following on these ways of multithreading performance to do a comparative summary.

First, suppose a business scenario in which multiple file objects are generated in memory, here tentative 30000, (Thread.Sleep (time)) thread sleep simulates the business logic of the processing of the threads, to compare the multithreading performance of these several ways.

1) Single Thread

This is a very simple approach, but the process is very time-consuming and can be very lengthy, because each thread waits for the current thread to execute before it executes, and it has little to do with multithreading, so it is very inefficient.

First create the file object with the following code:

public class FileInfo {private string filename;//file name private string filetype;//file type private string filesize;//file    Size private string FILEMD5;//MD5 code private string fileversionno;//file version number public FileInfo () {super (); } public FileInfo (string fileName, String FileType, String fileSize, String fileMD5, String fileversionno) {sup        ER ();        This.filename = FileName;        This.filetype = FileType;        This.filesize = fileSize;        THIS.FILEMD5 = fileMD5;    This.fileversionno = Fileversionno;    } public String GetFileName () {return fileName;    The public void Setfilename (String fileName) {this.filename = FileName;    } public String Getfiletype () {return fileType;    } public void Setfiletype (String fileType) {this.filetype = FileType;    } public String GetFileSize () {return fileSize;    } public void Setfilesize (String fileSize) {this.filesize = fileSize; } public String GetFileMD5 () {return fileMD5;    } public void SetFileMD5 (String fileMD5) {this.filemd5 = fileMD5;    } public String Getfileversionno () {return fileversionno;    } public void Setfileversionno (String fileversionno) {This.fileversionno = Fileversionno; }
View Code

Then, to simulate the business process, create 30,000 file objects, thread sleep 1ms, previously set 1000ms, found a long time, the entire Eclipse card dropped, so the time changed to 1ms.

public class Test {         private static list<fileinfo> filelist= new arraylist<fileinfo> ();         public static void Main (string[] args) throws Interruptedexception {                   createfileinfo ();                   Long Starttime=system.currenttimemillis ();                   for (FileInfo fi:filelist) {                            thread.sleep (1);                   }                   Long Endtime=system.currenttimemillis ();                   SYSTEM.OUT.PRINTLN ("Single Thread Time-consuming:" + (Endtime-starttime) + "MS");         }                 private static void Createfileinfo () {                   for (int i=0;i<30000;i++) {                            filelist.add (new FileInfo ("id", " JPG "," 101522 "," MD5 "+i," 1 "));}}}         
View Code

The test results are as follows:

As you can see, generating 30,000 file objects consumes more time, is close to 1 minutes, and is less efficient.

2) ThreadPool (thread pool) +countdownlatch (program counter)

As the name implies, Countdownlatch is the thread counter, and his execution is as follows: First, call the await () method in the main thread, block the main thread, and then pass the program counter as a parameter to the thread object, and finally, after each thread finishes executing the task, call Countdown () Method represents the completion of a task. Countdown () is executed multiple times, the main thread's await () is invalidated. The implementation process is as follows:

public class Test2 {private static Executorservice Executor=executors.newfixedthreadpool (100);    private static Countdownlatch countdownlatch=new countdownlatch (100);    private static list<fileinfo> filelist= new arraylist<fileinfo> ();        private static list<list<fileinfo>> list=new arraylist<> ();        public static void Main (string[] args) throws Interruptedexception {Createfileinfo ();        Addlist ();        Long Starttime=system.currenttimemillis ();        int i=0;            for (list<fileinfo> fi:list) {executor.submit (new filerunnable (countdownlatch,fi,i));        i++;        } countdownlatch.await ();        Long Endtime=system.currenttimemillis ();        Executor.shutdown ();    System.out.println (i+ "Thread Time:" + (Endtime-starttime) + "MS"); } private static void Createfileinfo () {for (int i=0;i<30000;i++) {Filelist.add (new FileInfo ("body        Copies of the positive photo "," jpg "," 101522 "," MD5 "+i," 1 "); }   } private static void Addlist () {for (int i=0;i<100;i++) {list.add (fileList); }    }}
View Code

Filerunnable class:

/** * Multithreading * @author WANGSJ * * @param <T> */public class Filerunnable<t> implements Runnable {          private C Ountdownlatch Countdownlatch;         Private list<t> List;         private int i;                 Public filerunnable (Countdownlatch countdownlatch, list<t> List, int i) {                   super ();                   This.countdownlatch = Countdownlatch;                   this.list = list;                   this.i = i;         }          @Override public         Void, run () {for                   (T t:list) {                            try {                                     thread.sleep (1);                            } catch ( Interruptedexception e) {                                     e.printstacktrace ();                            }                            Countdownlatch.countdown ();                   }         } }
View Code

The test results are as follows:

3) Fork/join Frame

JDK starting from version 7, there is a fork/join framework, literally understand that fork is split, join is merging, so the idea of the framework is. Split the task by fork, then join to merge the results of the split after each character's execution and summarize. For example, we want to calculate the number of consecutive additions, 2+4+5+7=? , we use the Fork/join framework to how to complete, the idea is to split the molecular task, we can divide this operation into two sub-tasks, a calculation 2+4, another calculation 5+7, this is the fork process, after the completion of the calculation, the results of the two sub-tasks summed up, to get the sum, This is the process of join.

Fork/join Framework Implementation idea: First, split the task, using the fork class to divide the large task into several subtasks, the segmentation process needs to be based on the actual situation, until the split task is small enough. Then, the join class performs the task, the split subtasks are in different queues, several threads get the task from the queue and execute, the results are placed in a separate queue, and finally, the thread is started, the queue takes the results and merges the results.

Using the Fork/join framework to use a few classes, about how the class can be used to refer to the JDK API, using the framework, the first need to inherit the Forkjointask class, usually only need to inherit his subclass Recursivetask or recursiveaction, Recursivetask, used for scenes with return results, recursiveaction for scenes with no results returned. The execution of the forkjointask needs to be performed with Forkjoinpool, which is used to maintain the split subtasks added to different task queues.

Here is the implementation code:

public class Test3 {private static list<fileinfo> filelist= new arraylist<fileinfo> ();    private static Forkjoinpool forkjoinpool=new Forkjoinpool (100);            private static job<fileinfo> job=new job<> (filelist.size ()/100, fileList);                public static void Main (string[] args) {createfileinfo ();        Long Starttime=system.currenttimemillis ();        Forkjoinpool forkjoinpool=new Forkjoinpool (100); Split Task job<fileinfo> job=new job<> (filelist.size ()/100, fileList);//Submit task return result Forkjointask<int Eger> fjtresult=forkjoinpool.submit (Job);//Block while (!job.isdone ()) {System.out.println ("task complete!        ");        } long Endtime=system.currenttimemillis ();    System.out.println ("Fork/join frame Time:" + (Endtime-starttime) + "MS"); } private static void Createfileinfo () {for (int i=0;i<30000;i++) {Filelist.add (new Fileinf O ("Positive photo ID", "JPG", "101522", "MD5" +i, "1"));  }}}/** * Perform task class * @author WANGSJ * */public class Job<t> extends recursivetask<integer> {private static        Final long serialversionuid = 1L;    private int count;        Private list<t> joblist;        public Job (int count, list<t> joblist) {super ();        This.count = count;    This.joblist = joblist; }/** * Performs a task similar to the Run method that implements the Runnable interface */@Override protected Integer Compute () {//Split task if (job            List.size () <=count) {executejob ();        return Joblist.size (); }else{//Continue to create the task until it is able to break down execution list<recursivetask<long>> fork = new Linkedlist<recursivetas            K<long>> ();            Split the molecular task, here using the dichotomy int countjob=joblist.size ()/2;            List<t> leftlist=joblist.sublist (0, Countjob);                        List<t> rightlist=joblist.sublist (Countjob, Joblist.size ()); Assign Task Job Leftjob=new job<> (count,lEftlist);                        Job rightjob=new job<> (count,rightlist);            Perform task leftjob.fork ();                        Rightjob.fork ();                    Return Integer.parseint (Leftjob.join (). ToString ()) +integer.parseint (Rightjob.join (). ToString ());            }}/** * Execute Task Method */private void Executejob () {for (T job:joblist) {            try {thread.sleep (1);            } catch (Interruptedexception e) {e.printstacktrace (); }        }    }
View Code

The test results are as follows:

4) JDK8 Parallel Stream

Parallel flow is one of the new features of Jdk8, and the idea is to make a sequential flow into a concurrent stream by calling the parallel () method. Parallel streams divide a stream into chunks of data, use different threads to process the streams of different chunks, and finally merge the processing results of each block data stream, similar to the Fork/join framework.

The parallel stream by default uses the common thread pool Forkjoinpool, his number of threads is the default value used, according to the machine's number of cores, we can appropriately adjust the size of the number of threads. The adjustment of the number of threads is implemented in the following way.

System.setproperty ("Java.util.concurrent.ForkJoinPool.common.parallelism", "100");

The following is the implementation of the code, which is very simple:

public class Test4 {private static list<fileinfo> filelist= new arraylist<fileinfo> ();p ublic static void main (string[] args) {          //                System.setproperty ("Java.util.concurrent.ForkJoinPool.common.parallelism", "+");           Createfileinfo ();           Long Starttime=system.currenttimemillis ();           Filelist.parallelstream (). ForEach (e->{                    try {                             thread.sleep (1);                    } catch (Interruptedexception f) {                             f.printstacktrace ();                    }                              });           Long Endtime=system.currenttimemillis ();           System.out.println ("Jdk8 Parallel stream time Elapsed:" + (Endtime-starttime) + "MS");} private static void Createfileinfo () {           for (int i=0;i<30000;i++) {                    filelist.add (new FileInfo ("id", " JPG "," 101522 "," MD5 "+i," 1 "));}}}           
View Code

Here is the test, the first time you have not set the number of thread pools, by default, the test results are as follows:

We see that the result is not ideal, takes longer, and then sets the size of the thread pool, adding the following code:

System.setproperty ("Java.util.concurrent.ForkJoinPool.common.parallelism", "100");

Following the test, the results are as follows:

This time is less time consuming, more ideal.

Iii. Summary

In several cases, a single thread as a reference, the longest time is the original Fork/join framework, although the number of thread pool configuration, but the effect of more accurate configuration of the number of thread pool JDK8 parallel stream poor. Parallel stream Implementation code is simple to understand, do not need us to write redundant for loop, a Parallelstream method all done, the code is greatly reduced, in fact, the bottom of the parallel stream is the use of the Fork/join framework, which requires us in the development process of flexible use of various technologies, Distinguish the advantages and disadvantages of various technologies, so as to better serve us.

Technical level is limited, you are welcome to criticize the guidance!

Source Address: Https://files.cnblogs.com/files/10158wsj/threadsDemo.zip

Java Multithreading optimization and usage

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.