Because some projects in the past need to write some high-performance servers, and the results are varied, we need to use NiO to write asynchronous servers, but some people have written NiO as synchronous, it is also written as a single batch processing, thread scheduling, communication, and synchronization operation, especially like the sky, which does not show any architecture, typical noodlesCodeAnd have to make up your mind to isolate the I/O part from the thread scheduling part.
Therefore, I carefully studied the NIO mechanism and the util. Concurrent package of DL.
1. Appearance of NiO
NIO is something that occurs only in jdk1.4. The biggest benefit it brings to everyone is asynchronous socket. For other files, pipe won't talk much about it for the moment.
Before jdk1.4 appears, if you need to write a Java Server, in order to implement asynchronous operations, you must generate a Java thread for each connection request. When there are many connection requests, the thread is scheduled, context switching is very expensive. Because Java is cross-platform, different platforms have different support for threads and different performance, therefore, the traditional Java Server programming architecture is inefficient and expensive. The DL hero wrote a util. after the concurrent package, the thread scheduling is reduced to JavaProgramCompared with the servers written in C and C ++, Java servers are basically not competitive when performance requirements are high, none of them even have the right to be shortlisted.
II. Implementation of asynchronous socket
After NiO appeared, it seemed that Java programmers had a chance to get angry with Yang Mei. How did they use it? What was the feeling of everyone at the time? I don't know, because I didn't do Java at the time, I have limited knowledge about Java.
NIO is an event-based Io architecture. The most basic idea is: I will notify you of events and you will do your things again, when there is no event, you can save a lot of time to do anything else. Besides, NiO's main thread is only one. Unlike the traditional model, it requires n threads, which reduces the workload of JVM and makes it more efficient for JVM to process tasks.
When I first came into contact with NiO, I was overwhelmed by the Channel architecture on layer N and the overwhelming praise on the Internet. I think it should also be a very mature product. There are so many online materials, copy jetty, tomcat, and otherSource codeYou can basically get it done. At this time, I didn't expect everyone to be so deeply affected by synchronization, or even write code without even figuring out the most basic asynchronous concepts, come up with a bunch of problems (this is what we will talk about later ).
After studying NiO, it is found that NiO is actually doing a very simple job in Java, that is, collecting and distributing events. We will use a classic call example to illustrate this problem, I will not start with the basic usage of NiO. You can check other materials.
After the channel is registered with selector, our most classic call method is like this.
1 While (Somecondition)
2 {
3 Int N = Selector. Select (timeout );
4 If (N = 0 ) Continue ;
5 For (Iterator ITER = Selector. selectedkeys (). iterator (); ITER. hasnext ();)
6 {
7 If (Key. isacceptable ())
8 Doacceptable (key );
9 If (Key. isconnectable ())
10 Doconnectable (key );
11 If (Key. isvalid () && Key. isreadable ())
12 Doreadable (key );
13 If (Key. isvalid () && Key. iswritable ())
14 Dowritable (key );
15 ITER. Remove ();
16 }
17 }
This is just a small example. I am too lazy to catch any exceptions.
The Event Notification obtained in NIO is completed in the selector select event. There is a thread in the selector event. The specific processing of this thread is simply to ask the operating system, the channel & selectionkey registered in selector occasionally checks whether various events occur. If yes, it is added to the selectedkeys attribute set of selector and returns the number of events of interest this time. The programmer finds that this value is greater than 0, indicating that an event has occurred. The programmer immediately iterates the selectionkey in selectedkeys and processes the event in the key.
In fact, this section shows the core of the asynchronous socket, that is, the asynchronous socket only sends the scheduling of multiple Sockets (or their thread scheduling) to the operating system for completion, asynchronous core selector only collects and distributes these scheduling tasks. Because the socket and thread scheduling in the operating system is more efficient than that in your JVM.
even if the JVM is as good as the operating system and has the same high performance (of course this is unrealistic), using asynchronous socket saves at least half of the system consumption, imagine that the operating system itself uses threads to maintain N socket connections. In traditional Java programming, you must add multiple Java threads for these sockets, it must be at least 2n threads. Now only n + 1 is required. In the case of high concurrency, think about it yourself.
now that we understand this truth, asynchronous socket is easy to write and will not confuse our thinking.
3. Notes in asynchronous socket
3.1 read
The most basic concept of asynchronous socket is Event Notification. As mentioned above, you should do what you should do only when Event Notification is triggered. When an op_read event is registered in an asynchronous socket, wait for selector to notify you. If no notification is sent, you can sleep at home.
Here, some of our errors are caused by synchronization. We read them on our own and made multiple threads. If we think about them carefully, we won't have this problem. In synchronous socket, when the read method is called to read the data in Io, it is usually blocked and synchronized if no data read method is available. Therefore, when multiple threads access the data at the same time, the read method is thread-safe.
In asynchronous mode, it is different. asynchronous mode will not be blocked. If there is anything, it will return something. If you actively read it, you can take it away as long as there is data. In the case of multithreading, maybe you want to let the first thread read the data. But when it comes to data, it happens that thread 2 has read the data, so thread 2 will happily take it, and thread 1 is still waiting, this leads to data confusion. If data is no longer provided, thread 1 is an endless loop.
2. Write
In asynchronous socket, writing is the only operation that actively performs, but cannot directly write the channel. Instead, you should first register yourself as op_writable, and then selector will discover your existence, and send a write event, you can write it later. However, there is a little trick at this time, that is, before you perform the write operation, please cancel your write registration, otherwise, your CPU must be 100%.
3. Waiting
In traditional Server programming, because each request is a thread, wait or sleep in each of your request threads will not affect others. But asynchronous mode is different. There is only one main thread. Basically, each processing is linear. That is to say, after processing the first thread, the second thread can be processed, therefore, NiO is an excellent architecture for handling transient connections.
The problem we have now is that some people are affected by synchronization, but they have not figured out how to handle Asynchronization. They actually use sleep in Method Processing, and the wait time is 3 seconds. What does this mean, it takes 3 seconds to process a request, my God. Why do I need a server that can process a request in 3 seconds? 1960s :(
In such a case, you should start another thread (the thread pool is recommended) to complete this "long" task, or submit the other tasks to a message queue, you can send messages to others to complete the operation. The client can wait. How can your server wait? Writing such code will basically waste a server.
In my personal mood, I am complaining about this blog. I think it is incredible for some people.