Distributing freebies: non-braking threads in Java. Project loom
Do you want threads in javka that do not eat memory as if they are not in themselves and do not slow down? Good laudable desire, and this issue answers this question.
We explain the work of Project Loom on pizza boxes! Fly!
Delivery scope:
- Videocast (main part). For those who like to consume video.
- Full text transcript of the article. There are links!
All this is removed and written specifically for Habr .
We live in a cruel new world where likes are worth more than money. A blogger can do almost anything for likes. The final stage of international capitalism and technological debauchery.
I know that your laychik gave you hard work. It is not known what abominations you generally do to make money. Perhaps you are responding to comments that you don’t really like, to people you hate, and that’s how you earn yourself the desired benefits. I do not want to know about it at all. Huskies do not smell. Just give me a little bit of likes, and I pretend I don’t know where they are from. That's all that matters to a sales blogger like me.
All little kids will go to create new content. Thank.
Call Signs
Hello, javana, Oleg is in touch.
Do you often see such a picture on your web service: at first everything was fine, then a million Chinese came to you, the service did a million threads and choked to hell with the dogs?
Do you want just such a nice picture?
In other words, do you want threads in javka that do not guzzle memory if they are not in themselves and do not slow down? Good laudable desire, and this issue answers this question.
We will deal, in fact, with unpacking the new framework . Remember how Wylsacom unpacked iPhones? Some people no longer remember the old reviewers, but why? Because Habr is a mainstream stronghold, and the paid vidos are, excuse me, the rays of diarrhea . In this post we will deal exclusively with technical hardcore.
First two minutes for a string, a disclaimer and other stuff that needs to be said. You can skip it if you are too lazy.
First, everything said in the video is my personal thoughts, and they have nothing to do with the employer or the glorious Oracle Corporation, the world government of lizards and the line in a mortar. I even write it at three o'clock in the morning, so that it was clearly clear that this is my personal initiative, my personal garbage. All matches are purely random.
But there is another bonus goal. We constantly talk about korutinakh in Kotlin. Recently there were interviews with Roma Elizarov , the god Korutin, and with Pasha Finkelstein , who is going to write backends for them. Soon there will be an interview with Andrei Breslav - who is the father of Kotlin. And everywhere the project Loom is somehow mentioned, because it is an analogue of corutin. And if you don’t know what a Loom is, you may become dumb when reading these interviews. There are some cool dudes, they discuss cool things. And there you are, and you are not with them, you are a schmuck. This is very stupid.
Do not do this, read what Loom is, in this article, or continue to watch this video, I'll explain everything.
So, what's the plot. There is such a dude, Ron Pressler.
Last year, he went to the newsletter , stated that the threads in java sucked, and suggested that I run the runtime and fix it. And everyone would have laughed at him and threw stones at him, by shit, if not for the fact that he had previously written Quasar , and this is actually very cool. You can swear at Quasar for a long time, but it seems to be there and it works, and in the big picture of all this is rather an achievement.
There are a damn number of govnoderov who do nothing, just say. Well, understand correctly, I'm the same. Or there are people who seem to be cool engineers, but in general, unconsciously, they say: “In Java it is necessary to improve the threads.” What to improve? What are threads?
People in general are too lazy to think.
How's the joke:
Petka and Vasily Ivanovich are flying in the plane.
Vasily Ivanovich asks: - Petka, devices?
Petka answers: - 200!
Vasily Ivanovich: - And what about 200?
Petka: - And what about the devices?
I'll tell you a story. I was in Ukraine this spring, we flew from Belarus (you understand why it is impossible directly from St. Petersburg). And at the customs, we sat for about two hours, no less. The customs officers are very nice, seriously asking if Java is an outdated technology. Nearby sat people who fly on the same konfu. And I'm the same type of speaker, I have to pantanutsya, I stand and, as expected, shamelessly talk about things that I do not use at all. Along the way, I talked about the JDK distribution called Liberica, which is such a JDK for the Raspberry Pi.
And what do you think. Not half a year goes by, as people are knocking on my cart and saying that, look, we wrote a solution in Prod on Liberica, and I already have a report on this at the Belarusian jfu.by. This is the approach. This is not some lousy evangelist, but man, man, man, man, man.
By the way, we will soon have the Joker 2018 conference , which will include Andrei Breslav (obviously, fumbling in the korutinakh), and Pasha Finkelstein , and you can ask Josh Long about supporting Loom in Spring . Well and still a lot of cool prominent experts, fly around!
And now, going back to threads. People are trying to hold a thought through their degraded two neurons, they wind snot on their fists, and mumble: "The threads are not right in Java, the threads are not in Java". Devices! What appliances? This is generally hell.
And here comes Presler, a normal dude, not degraded, and first makes a sane description. A year later, sawing a working demo. All this I said, so that you understand that a normal description of problems, normal documentation is such a special kind of heroism. A demo - it's all space. This is the first person who ever did something in this direction. He needs the most.
Together with the demo, Pressler spoke at the conference and released a video like this:
In fact, this entire article is a review of what was said there. I absolutely do not pretend to the uniqueness of this material, everything that is in this article came up with Ron.
The discussion is about three painful topics:
- Contributions
- Fibers
- Tail calls
Probably, he was so zadolbalo sawing Quasar and fight with his glitches, that now there is no strength - you have to shove it into runtime.
It was a year ago, and since then they sawed a prototype. Some have already lost hope that we will see the demo sometime, but a month ago they gave birth to her and showed what is visible on this tweet .
All three painful topics in this demo are either directly in the code, or at least are present morally. Well, yes, they haven’t mastered tail calls yet, but they want to.
Problematics
Unhappy users, application developers, when they do an API, are forced to choose between two chairs. Peaks are embedded in one chair, flowers grow on the other. And neither one nor the other does not suit us.
For example, if you write a service that works synchronously, it works great with legacy code, it is easy to debug and monitor the performance. Problems arise with bandwidth and scalability. Just because the number of threads that can now be run on a simple piece of hardware, on the commodity hardware - well, let's say, two thousand. This is much less than the number of connections that can be opened to this server. Which in terms of netcode can be almost infinite.
(And yes, it has something to do with the fact that in Java sockets arranged debility , but it's a topic for another conversation)
Imagine you are writing some MMO.
For example, during the Northern War in EVE Online, two thousand four hundred pilots gathered at one point in space, each of which - conditionally, if it were written in Java - there would be more than one thread. And the pilot, of course, is a complex business logic, and not the issuance of some HTML, which can be smothered with your hands in a magnifying glass.
The response time in that battle was so long that the player had to wait a few minutes to wait for a shot. As far as I know, CCP specifically threw the huge hardware resources of its cluster for that battle.
Although, I probably use EVE as an example in vain, because, as far as I understand, everything is written in Python, and in Python with multithreading it is still worse than ours - and it can be considered a bad concurrence of language features. But the example is clear and with pictures.
If you are interested in the subject of MMOs in general and the history of the “Northern War” in particular, recently a very good video on this topic appeared on the BULDJAT channel (whatever the name means), look from my time mark.
Back to the topic.
On the other hand, you can use any asynchronous framework. It scales. But we will immediately get to a very complex debugging, complex profiling of the performance, we will not be able to integrate it seamlessly with Legacy, we will have to rewrite a lot of things, wrap in nasty wrappers, and generally feel like we were just raped. Several times in a row. All day long, in fact, all the time while we are writing this, we will have to feel this way.
I asked an expert, a well-known academician Escobar, what he thinks about this:
What to do? So-called faybery are in a hurry to help.
In general, faibers are such light threads that also scoop address space (because there are no miracles, you understand). But unlike conventional threads, they are not using preemptive multitasking, but cooperative multitasking. More worth reading on Wikipedia .
Faybery can realize the advantages of both synchronous and asynchronous programming. As a result, hardware utilization is improved, and we use fewer servers in the cluster for the same task. Well, in the pocket for this we get lavender. Babosy. Lave Money. Well, you understand. For saved servers.
At the crossroads
The first thing I want to discuss. People do not understand the difference between Continuations and Faybers.
Now will be Cultural enlightenment!
Let's announce the fact: Continuation and Fiber are different things.
Continuations
Fiber is built on top of mechanics called Continuations.
Continuations (more precisely, delimited continuations) is a kind of calculation, execution, a piece of a program that can fall asleep, then wake up and continue execution from the place where it fell asleep. He can sometimes even be cloned or serialized, even while he is sleeping.
I will use the word “continuation” and not “continuation” (as it is written on Wikipedia), because we all communicate in English . Using normal Russian terminology, one can easily come to a situation when the difference between a Russian and an English term becomes too large and no one else understands the meaning of what has been said.
I will also sometimes use the word “crowding out” instead of the English version of “yield”. Just the word "yield" - it is some kind of really very gruesome. Therefore, there will be "crowding out."
So here. It is very important that there should be no concarrency within the continuum. It is in itself the minimum primitive of this process.
You can think of continuation as o Runnable
, in which you can call a method inside pause()
. It is inside and directly, because we have cooperative multitasking. And then you can run it again, and instead of counting everything anew, it will continue from the place where it stopped. Such magic. For magic, we will return.
Where to get a demo with working continuations - we will discuss at the very end. Now let's talk about what is there.
The class itself is a continuation to the address in java.base, all links will be in the description. ( src/java.base/share/classes/java/lang/Continuation.java
) But this class is very large, voluminous, so it makes sense to look only at some sort of squeeze from it.
publicclassContinuationimplementsRunnable{
publicContinuation(ContinuationScope scope, Runnable body);
publicfinalvoidrun();
publicstaticvoidyield(ContinuationScope scope);
publicbooleanisDone();
protectedvoidonPinned(Reason reason){
thrownew IllegalStateException("Pinned: " + reason);
}
}
Note that in fact this file is constantly changing. For example, as of the previous day, the continuation did not implement the interface Runnable
. Treat this as some kind of sketch.
Take a look at the constructor. body
- this is the code that you are trying to run, and scope
- this is a kind of OSP, which allows you to put a continuation in a continuation.
Accordingly, it is possible either to bite this code to the end with a method run
, or to force it out with some specific ensemble using the method yield
(the skip is needed here for something like forwarding exceptions over nested handlers, but it doesn't matter to us as users). You can ask using the method isDone
, whether everything is completed.
And for reasons dictated solely by the needs of the current implementation (but most likely, the release will also get), it is not always possible to do yield
. For example, if inside the continuation we had a transition to the native code and a native frame appeared on the stack, then it cannot be loaded. This will also happen if we try to force out while a native monitor is taken inside the body of the continuation, such as a synchronized method. By default, when you try to do this, an exception is thrown ... but the faders built on top of the continuations overload this method and do something else. This will be a little later.
You can use it like this:
Continuation cont = new Continuation(SCOPE, () -> {
while (true) {
System.out.println("before");
Continuation.yield(SCOPE);
System.out.println("after");
}
});
while (!cont.isDone()) {
cont.run();
}
This is an example from the Pressler presentation. Again, this is not “real-life” code, it's some kind of sketch.
This is a sketch of what we are doing a continuation, in the middle of this continuation we are crowded out and then in an endless cycle we ask whether the continuation worked to the end and whether it should be continued.
But in general, it is not assumed that ordinary application programmers will touch this API. It is intended for creators of system frameworks. System frameworks like the Spring Framework will immediately fix this feature as soon as it is released. You will see. Take this as a prediction. Such a light prediction, because here everything is pretty obvious. All data to predict there. This is too important a feature not to be bullied. Therefore, it is not necessary to worry in advance that someone will torture you by coding in this form. Well, if you are a Spring developer, you knew what you were going for.
And now the faybers are built on top of the continuations.
Fibers
So, what in our case means faybery.
This is a kind of abstraction, which is:
- Lightweight threads that are processed in the JVM itself, and not in the operating system;
- With extremely low overheads on creating, maintaining life, switching tasks;
- Which can be run millions of times.
Many technologies are trying to make faibers in one way or another. For example, in Kotlin there are Korutins implemented on a very smart generation of bytecode. VERY SMART . But runtime is a better place to do things like that.
At a minimum, the JVM already knows how to cope well with threads, and all we need is to simplify the multithreading coding process. You can use asynchronous APIs, but this can hardly be called “simplification”: even the use of such things as Reactor , Spring Project Reactor, which allow you to write seemingly linear code, will not help much if you need to debug complex problems.
So, fayber.
Fiber consists of two components. It:
- Continuation (Continuation)
- Scheduler
I.e:
- Continuation
- Scheduler
You can decide who the planner is here. I think the planner here is Jay.
- Fiber wraps the code you want to execute in a continuation
- The scheduler runs them on the pool of carrier threads
I will call them carrier threads.
The current prototype is used java.util.concurrent.Executor
, and the built-in scheduler is used ForkJoinPool
. We have everything. In the future, there may appear something smarter, but so far like this.
How the continuation behaves:
- It is forced out (yield) when there is a lock (for example, on IO);
- It continues when it is ready to continue (for example, the IO operation has completed and you can move on).
Current status of work:
- The main focus on philosophy, concepts;
- API is not fixed, it is "for show". This is a research prototype;
- There is a ready coded working class prototype
java.lang.Fiber
.
About him will be discussed.
What is already filed in fayber:
- It runs the launch tasks;
- Parking anparking on a thread carrier;
- Waiting for the fayber to complete.
Schematic diagram
mount();
try {
cont.run();
} finally () {
unmount();
}
- We can mount the fayber on a thread carrier;
- Then start the continuation;
- And wait until it is crowded out or honestly stops;
- In the end, we always leave the thread.
This pseudocode will run on the scheduler ForkJoinPool
or on some other (which will eventually end up in the final version).
Use in reality
Fiber f = Fiber.execute( () -> {
System.out.println("Good Morning!");
readLock.lock();
try {
System.out.println("Good Afternoon");
} finally {
readLock.unlock();
}
System.out.println("Good Night");
});
Look, we create a file in which:
- welcome everyone;
- block on the reentrant lock;
- on return we congratulate with lunch;
- finally letting go of lok;
- and say goodbye.
Everything is very simple.
We do not cause displacement directly. Project Loom itself knows that when it is triggered, readLock.lock();
it is worth it to intervene and implicitly make crowding out. The user does not see this, but it happens there.
Stacks, Stacks Everywhere!
Let's use the example of a pizza stack to demonstrate what is happening.
Initially, the thread is in the idle state, and nothing happens.
Top of the stack at the top, remember.
Then the fayber was scheduled for execution, and the fayber task began to run.
Inside himself, he obviously starts a continuation in which the real code is already located.
From the user's point of view, we haven't run anything here yet.
That's just the first frame of the user code appeared on the stack, and it is marked in purple.
Next, the code is executed-executed, at some point the task is trying to capture the lock and get locked up on it, which leads to automatic displacement.
Everything that is on the continuation stack is stored in a kind of magical place. And disappears.
As you can see, the stream returns to the fayber, on the instruction that comes next Continuation.run
. And this is the end of the fayber code.
Task faybera ends, thread carrier is waiting for a new job.
The fayber is parked, somewhere lies, the continuation is completely crowded out.
Sooner or later there comes a time when the one who owns the lock releases it.
This leads to the fact that the fayber, which was waiting for the release of the Lok, is encased. The task of this file is started again.
- ReentrantLock.unlock
- LockSupport.unpark
- Fiber.unpark
- ForkJoinPool.execute
And we quickly return to the stack that was recently.
And the thread carrier may be completely different. And that makes sense!
Run the continuation again.
And here happens the MAGIC !!! The stack is restored, and execution continues with instructions after Continuation.yield
.
We get out of the newly parked Lok and begin to execute the rest of the code remaining in the continuation:
The user task is completed, and control returns to the task file immediately after the continuation.run instruction.
At the same time, the execution of the fayber ends, and again we find ourselves in the standby mode.
The next launch of the fieber again initiates the entire cycle of rebirths described above.
Living examples
And who ever said that it all works? Is it about a couple of microbench marks written over the evening?
As an example of the work of the faders, the Oraklovites wrote a small web server and fed it with queries so that it choked. Then transferred to the faybery. The server ceased to choke, and from this it was concluded that the filers are working.
I don’t have the exact code of this server, but if this post has enough likes and comments, I’ll try to write an example myself and build real charts.
Problems
Are there any problems here? Yes of course! The whole story with the faybers is a story about continuous problems and tradeoffs.
Philosophical problems
- Do we need to reinvent threads?
- Should all existing code work normally inside a file?
The current prototype performs with limitations. Which may go into release, although I would not want to. Still, OpenJDK is a thing that respects infinite compatibility.
What are the technical limitations? The most obvious limitations are 2 pieces.
The problem is once - you can not force out native frames
PrivilegedAction<Void> pa = () -> {
readLock.lock(); // may park/yieldtry {
//
} finally {
readLock.unlock();
}
returnnull;
}
AccessController.doPrivileged(pa); //native method
Here, doPrivileged is calling the native method.
You call in a fayber doPrivileged
, jump out of VMki, you have a native frame on the stack, after which you try to park on the line readLock.lock()
. And at this moment the thread carrier will be stumbled until such time as it is unpacked. That is, the thread disappears. In this case, the carrier threads may end, and in general, it breaks the whole idea of the faders.
The way to solve this is already known, and now there are discussions about this.
Problem two - synchronized blocks
This is a much more serious garbage.
synchronized (object) { //may park
object.wait(); //may park
}
synchronized (object) { //may park
socket.getInputStream().read(); //may park
}
In the case of a monitor capture in a fayber, the carrier threads are also kicked.
It is clear that in a completely new code you can change monitors for direct blocking, instead of wait + notify, you can use condition objects, but what to do with Legacy? This is problem.
Thread API? Thread.currentThread ()? Thread Locals?
In the current prototype for Thread
and Fiber
made one common superclass called Strand
.
This allows you to migrate the API in the most minimal version.
What to do next - as always in this project, the question.
What is happening with Thread API?
- The first use
Thread.currentThread()
in a fayber creates a certain shadow thread, Shadow Thread; - from the point of view of the system, this is an "unreleased" thread, and there is no VM meta-information in it;
- ST tries to emulate everything that it can;
- but you need to understand that the old API has a lot of garbage;
- More specifically, Shadow Thread implements Thread API for everything except
stop
,suspend
,resume
and processing uncaught exceptions.
What to do with Thread Locals?
- now thread locals just turn into fiber locals;
- there are so many problems with this, everything is discussed;
- The set of uses is discussed especially;
- threads historically used both correctly and incorrectly (those who use incorrectly still hope for something, and they cannot be completely disappointed);
- in general, it creates a range of applications:
- High-level: cache of connections or passwords in a container;
- Low-level: processor in system libraries.
How much does it all eat?
Thread:
- Stack: 1MB and 16KB on kernel data structures;
- Per thread instance: 2300 bytes, including VM meta information.
Fiber:
- Continuity stack: from hundreds of bytes to kilobytes;
- On an instance of a fayber: 200-240 bytes.
The difference is colossal!
And this is exactly what allows Faybara run millions.
What can park
It is clear that the most magical thing is automatic parking upon the occurrence of some events. What is supported now?
- Thread.sleep, join;
- java.util.concurrent and LockSupport.lock;
- IO: network on sockets (socket read, write, connect, accept), files, pipes;
- All this is unfinished, but the light in the tunnel is visible.
Communication between faybery
Another question that everyone asks is: how to exchange information concurrently between file servers.
- The current prototype launches the task in
Runnable
, you can remake onCompletableFuture
, if for some reason you need; - java.util.concurrent "just works." You can fumble all the standard way;
- there may be new APIs for multithreading, but this is not certain;
- a bunch of small questions like "should faybers return values?"; Everything is discussed, they are not in the prototype.
How are the continuations implemented in the prototype?
Obvious requirements are imposed on the continuation: you need to use as little RAM as possible, and you need to switch between them as quickly as possible. Otherwise it will not be possible to keep them in millions. The main task here is to somehow not do a full stack copying for each parking anapark. And there is such a scheme! Let's try to explain it in pictures.
The coolest way would be, of course, just put all the stacks on the java hip and use them directly. But it is not clear how to code now, so copying is used in the prototype. But copying with a small but important hack.
We have two chairs ... I mean, two stacks. Two java arrays in heap. One is an object array, where we will store references to objects. The second is a primitive (for example, intovy), which will handle everything else.
We are now in a state where the continuation is about to be carried out for the very first time.
run
calls the internal method called enter
:
And then the user code is executed, up to the first crowding out.
At this point, a call is made to the VM that is calling freeze
. In this prototype, this is done directly physically - using copying.
Begin the process of sequentially copying frames from the native stack to the java heap.
It is imperative to check whether the monitors are sticking there or if the native code is being used, or something else that will actually prevent us from continuing to work.
And if everything is fine, we first copy to a primitive array:
Then we extract the references to the objects and save them into the object array:
Actually, two teas to all who read to this place!
Then we continue this procedure for all other elements of the native stack.
Hooray! We copied everything into a hip stash. You can safely jump into a place of challenge, without fear that we have lost something. All in hip.
Now, sooner or later, the calling code will call our continuation again. And it should continue from the place where it was left last time. This is our task.
A check on whether the continuation was launched says - yes, it was launched. So you need to call the VM, clean up some space on the stack and call the internal VM function thaw
. In Russian “thaw” is translated as “thaw”, “defrost”, which sounds quite logical. You need to defrost frames from the continuation stack to our main native stack.
Not sure that the defrosting of tea looks quite clearly. Bad abstraction is like a kitten with a door. But we and such will fit.
We make quite obvious copies.
First, from the primitive array:
Then from the reference:
You need to patch a little to get the correct stack:
We repeat indecency for all frames:
Now you can go back to yield
and continue as if nothing had happened.
The problem is that full stack copying is absolutely not what we would like to have. It is very inhibitory. All this is the isolation of links, checks for pinning, it is not fast. And most importantly - it all depends linearly on the size of the stack! In a word, hell. Don't do that.
Instead, we have another idea - lazy copying.
Let's roll back to the place where we already have a frozen continuation.
We continue the process as before:
In the same way, as before, we clean the place on the native stack:
But we copy not everything, but only one or a couple of frames:
Now hack. You need to patch the return address of the method C
so that it points to some return barrier:
Now you can safely return to yield
:
Which in turn will lead to calling the user code in the method C
:
Now imagine that you C
want to return to the code that caused it. But his caller is this B
and he is not on the stack! Therefore, when he tries to return, he will go to the return address, and this address is now the return barrier. And, well, you understand, it will pull the challenge again thaw
:
And thaw
we will defreeze the next frame on the continuation stack, and this B
:
In fact, we copied it lazily, on request.
Next, we drop the B
continuation from the stack and set the barrier again (the barrier must be set, because there is some continuation on the continuation stack). And so time after time.
But imagine that B
it is not going to return to the calling code, but at first it calls some other method D
. And this new method also wants to be crowded out.
In this case, when the time comes to do freeze
, we will need to copy only the top of the native stack to the continuation stack:
Thus, the amount of work done does not depend linearly on the size of the stack. It linearly depends only on the number of frames that we actually used in our work.
What is left?
Some developers keep the features in mind, but they did not get into the prototype.
- Serialization and cloning. Ability to continue on another machine, at another time, etc.
- JVM TI and debug as if they were normal threads. If you are blocked on reading the socket, then you will not see a beautiful jump from yield, in the prototype, the thread will simply block, like any other ordinary thread.
- No one touched tail recursion.
Next steps:
- Make a human API;
- Add all missing features;
- Improve productivity.
Where to get
The prototype is made as a brunch in the OpenJDK repository. You can download the prototype here by switching to the brunch fibers
.
This is done like this:
$ hg clone http://hg.openjdk.java.net/loom/loom
$ cd loom
$ hg update -r fibers
$ sh configure
$ make images
As you understand, all this will start the assembly of the whole damn OpenJDK. Therefore, firstly, the next half hour of your life will have to do something else while it is all going.
Secondly, you need to have a normally configured computer with C ++ tulchein and GNU libs. I hint that it is strongly discouraged to do this on Windows. Seriously, even with the download of VirtualBox and the installation of a new Ubuntu, you will spend less time on orders than trying to realize the next non-humanoid error when building from Cygwin or msys64. This is the moment when msys comes in even worse than Cygwin.
Although this, of course, is all a lie, I just got bored with writing you instructions on assembling .
If you are going to change something in the source, I recommend to include a mercurial extension called fsmonitor. Read what it is, you can command hg help -e fsmonitor
.
To enable it, add the following line to ~ / .hgrc:
[fsmonitor]
mode = on
Many in some unimaginable way manage to spoil the downloaded repository during the first minutes of use. I therefore recommend that in any case immediately after downloading the whole daddy copy somewhere cp -R ./loom ./loom-backup
.
As usual, we change the place on the hard disk for possible lost hours of life. I think that the average Java-developer gets a lot of dough to properly prioritize this issue.
sh configure
sometimes will ask to do something. For example, if you have freshly installed Ubuntu, then it will ask you to install Autoconf ( sudo apt-get install autoconf
). This is one of the pleasures of building OpenJDK on fresh Ubuntu, many problems have already been told to you how to solve There will not be as good hints in Windows, if at all.
See what the difference between the branches, you can team hg diff --stat -r default:fibers
.
In general, a detailed analysis of what he saw in the differential deserves a completely separate philosophical article, a separate issue of the podcast, and now it is pointless to discuss it.
Conclusion
Fayber in English means "fiber, thread." Hence the word "microfiber", for example. “Loom” is a “loom”. In Project Loom, we will weave our code as a canvas from the fayberov.
But even with these innovations, modern multi-threaded programming looks like antediluvian, because it requires a lot of extra effort and awareness. The fact that now we can launch “threads” at once in millions does not mean that we don’t need to think at all - we must think, but, fortunately, much less.
It is symbolic that it was those who weaved on hand looms in the first quarter of the 19th century that they rushed to break the automation, which was then created for the cheap production of stockings.
And we have cheap production threads. In my opinion, the analogy is transparent.
I hope that one day all this will be replaced with even simpler and cheaper mechanisms in relation to the thinking of the developers. All this will be done by Artificial Intelligence inside the IDE and so on.
And at the moment it will be possible to enjoy not only the faybery, but also juicy bukurtom of St. Concarrency's Witnesses, who will tell us that all this is “not necessary”, “slows down”, “manually clearer” and so on.
And what do you think about this? Write in the comments. Delight the old man.
Thank.