First experience of multi-threading

First experience of multi-threading

​ The three assignments in the second stage were quite miserable. I couldn’t find other people’s bugs, but they kept being bugged by others. However, the attitude of the mutual testers encountered in these three assignments was really friendly, 2333. Well, let's analyze the three homework codes one by one.


The fifth assignment - multi-thread elevator

​ There are 5 practical classes in this assignment. Of course, there are other auxiliary enums, or classes for simply passing data, which are relatively simple. Recall that the writing of this homework was quite embarrassing, or because the initial design was not well thought out. Initially, I thought that the elevator this time processes requests in real time, so one request can be processed as soon as it comes, so the method of putting the input receiving thread and the assigning request thread in the same thread is adopted. After this design was done, I realized that it couldn't handle requests that were entered later but could be answered first because of piggybacking. This is a very unfortunate mistake, because piggybacking is a problem that has been emphasized in these elevators. This design error has led to subsequent major revisions.

​ There is a big difference between this assignment and the designs of the surrounding students. Because I like the feeling that the three elevators are sweeping the snow in front of the door, I adopted an internal class in the elevator, which is the SelfManager with "internal" in the class diagram. At the same time, SelfManager also inherits the scheduler of the previous jobs. In order to keep the class diagram concise, it is not reflected. Another inner class is BlockedRqManager, which is a thread that had to be added later due to a design error, specifically to deal with piggybacking problems.

From the class diagram, Elevator and Request have the most attributes and methods, but they are actually simple actions with a small amount of code. The main difficulty should be on SelfManager and RequestLoader. SelfManager has three threads, which operate three elevators respectively, which are used to traverse the request queue and select their own requests to guide the elevators to respond to the requests; this part is about 120 lines of code, which is actually not much. RequestLoader accepts incoming requests and decides to add it to the request queue or to the blocking queue according to whether there is currently an elevator available to respond to the request. Due to the concept of the blocking queue that was added later, the BlockedRqManager thread had to be added to manage the blocking queue.

​ This homework felt that the design mistakes were relatively large, but the final bug was not in the design scheme, but in the input and output issues. The output format of the invalid request misses the time T and QAQ; in order to keep the output system time consistent with the elevator time, it adopts the time calculated by itself instead of directly outputting the current system time. There is another question that is really insightful. Considering that the amount of information to be extracted from an input is relatively large, regular expressions are not used, but the data is extracted piece by piece. The problem lies in the String.split() method.

String str = "hello,,world,,,";
String[] jar = str.split(',');
for(String tmp :jar) {
    System.out.println("#"+tmp+"#");
}
// 我原本以为会这样输出
#hello#
##
#world#
##
##
##

// 实际是这样输出的
#hello#
##
#world#

I tried to use the length of the jar to judge the extra symbols at the end, but it didn't work, which resulted in the illegal request being treated as a legitimate request. Emmm, for this, I will definitely write regular expressions honestly in the future.


The sixth operation - file monitoring system

​ After analyzing the instruction book for a long time, I feel that due to various limitations, the homework does not seem to be that difficult. But it's actually quite a problem.

​ Speaking to the class diagram, the design idea is still very straightforward. A Monitor will hold a trigger FlipFlop and an Action; the Monitor thread continuously judges whether there is a corresponding file change by calling the detect() method of FlipFlop, and if there is a corresponding change, it calls the Action's act() method . I feel that this idea is very consistent with the mode of ifttt. Both FlipFlop and Action are abstract classes with their own specific subclasses that implement the detect() and act() methods respectively. As for ThreadSafeFile, considering that many class locks are required for file operations, a purely static class is provided, and only static methods are provided.

​ The amount of code this time can be clearly seen from the class diagram. FlipFlop has contracted a lot of code, and some of the code is simply a class for storing data, so there is no need to repeat it. There is actually a problem this time, because at the beginning, considering that Modified and sized-changed may need to continue to monitor the renamed and path moved files, the methods findRenameTarget() and findPathTarget() are put into the parent class to implement. Finally, it is shown that these two methods are only used by renamed and path-changed, so it is not appropriate to put them in the parent class, which increases the size of the parent class. Finally, FlipFlop reaches about 250 lines, and its subclasses look like 60 lines on average.

​ The bug in this homework is purely because I am fascinated. Because the snapshot saves all file information, deleted, moved, and renamed files will also be saved, which leads to the fact that after the changed file is reported once, the file will continue to be reported. The tester describes it as "crazy virtual area", which is appropriate. Obviously it is an obvious bug, and I don't know why it was not detected at the time. Maybe the focus was on solving the thread uncertainty problem caused by recovery.


The seventh operation - taxi system

​ This time, my own design feels a little more magical. Because I feel that the last request needs to maintain a 3s order grab window, it is better for a request to have its own thread for 3s, so that it is very convenient to complete the dispatch of the request. What unknown problem is caused by too many threads.

It is also because of the way of writing one request for one thread that the classes are relatively balanced. The Manager, which had to undertake more tasks, shared a considerable part of it with TaxiTask.

​ This operation encountered a multi-threaded pit, and two requests were allocated to different elevators. At first, I thought that the path was wrong. After a long time of research, I found that the synchronization and mutual exclusion were not handled properly. Later, I thought of what the operating system said, test lock and set, and turning it into an atomic operation can avoid this problem.

​ This time, I feel that there is no problem with the function, but I am not careful, and I have not completed the request that the starting point and the request point are ignored.


​ The homework at this stage is really bad, maybe because the difficulty has increased, and there is a reason why my enthusiasm has declined a bit. Well, the next stage still needs to continue to work hard. Especially in the design scheme, it is still necessary to carry out a specific feasibility analysis of the design scheme before carrying out the operation.

​ I remember the days before I wrote the multi-threaded elevator, and I was not very worried about the upcoming multi-threading. I found a copy of "Thinking In Java" and turned a few pages in a hurry. Later, when I wrote it, I found that it was completely different from what I used. So after writing multi-threading assignments three times, I still feel that I have no understanding of the concept of multi-threading and java. Little is known about multithreading in . Well, this is also to continue to study in depth.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325112600&siteId=291194637