Welcome to the first part of the guidelines for parallel programming in Java 8. In this section we look at simple examples of how to execute code in parallel by a flow of tasks and services of performers.
For the first time Concurrency API was introduced with the release of Java 5, and since then has evolved with each version of Java. Most of the examples can be implemented in older versions, but in this article I'm going to use lambda expressions. If you are still not familiar with the innovations of Java 8, I recommend to see myguide.
Streams and objectives
All modern operating systems support parallel execution of code using the processes andflows. The process - an instance of a program that runs independently of the others. For example, when you run a program in Java, the operating system creates a new process that runs parallel to the others. Within the processes we use flows, thereby to squeeze out the maximum processor capacity.
Streams (threads) in Java are supported starting with JDK 1.0. Before you start a thread, it is necessary to provide a piece of code, which is usually called a "challenge» (task). This is done by implementing the interface
Runnable, which has only one method with no arguments, returns void - run (). Here is an example of how this works:
Because the interface
Runnable function, we can use lambda expressions, which appeared in Java 8. In the example we create a task that displays the name of the current stream to the console, and run it first on the main thread, and then - in a separate.
The result of this code might look like this:
or so:
Due to the parallel execution, we can not say to our current run before or after the withdrawal of «Done!» On the screen. This feature makes parallel programming difficult in larger applications.
Threads can be suspended for some time. This is very useful if we want to simulate a long-running task. For example:
When you run this code, you will see a second delay between the output of the first and second line on the screen.
TimeUnit - a useful class for working with time units, but the same can be done with Thread.sleep (1000).
Working with streams directly uncomfortable and fraught with errors. Therefore, in 2004, we added in Java 5 Concurrency API. It is in the package
java.util.concurrent contains many useful classes and methods for multi-threaded programming. Since Concurrency API is continuously developing and evolving.
Let us now take a closer look one of the most important parts of Concurrency API - Service performers (executor services).
Artists
Concurrency API introduces the concept of service of the Executive (ExecutorService) - a high-level replacement with threads directly. Artists perform tasks asynchronously and usually use the thread pool, so we do not have to create them manually. Everything flows from the pool will be used again after the task, and therefore, we can create problems in the application as much as we want, using one performer.
That will look like our first example of using the artist:
Class
Executors provides convenient factory methods to create a variety of services artists. In this case, we used a performer with a single thread.
The result looks just like last time. But this code is an important difference - it never stops. The work necessary to complete the performers clearly. For this interface
ExecutorService there are two methods: shutdown (), which waits for the running tasks and shutdownNow (), which stops the artist immediately.
That is how I prefer to stop the singers:
Artist tries to shut down, waiting for the completion of the running tasks for a certain period of time (5 seconds). After this time he stopped interrupting all pending tasks.
Callable and Future
Also
Runnable, performers may take a different kind of problems, called Callable. Callable - it is also functional interface but, unlike Runnable, it can return a value.
Let's write a task that returns an integer after a moment:
Callable-tasks can also be transferred to the performers. But how to get the result that they return? Since the method
submit () does not wait for completion of the task, the Executive can not return a result of the problem directly. Instead, the artist returns a special object Future, which we will be able to request the result of the task.
After sending the task executor we first check whether its execution is completed, the method
isDone (). Since the problem has a delay of one second before you return the number, I am more than sure that it is not yet completed.
Calling
get () blocks the thread, and waits for the task, and then return the result of its implementation. Now future.isDone () returns true, and we will see in the console as follows:
Tasks are rigidly connected with the service of artists, and if you stop it, try to get the result of problem will throw an exception:
You may have noticed that this time we create a service a little differently: by the method
newFixedThreadPool (1), which will return the artist with a pool in one stream. This is equivalent to calling newSingleThreadExecutor (), but we can change the number of threads in the pool.Timeouts
Any method call
future.get () blocks the thread until then, until the task is completed. In the worst case, the task will not end ever, blocking your application. This can be avoided by passing the timeout:
Running this code will cause TimeoutException:
You have probably already guessed, why this exception was thrown: we specify the maximum waiting time of the task in one second, while its execution takes two.
InvokeAll
Artists can make a list of tasks to perform using the method
invokeAll (), which takes a collection of callable-tasks, and returns a list of the Future.
In this example, we used a functional Java threads 8 to handle tasks that were returned byinvokeAll. We walked all the problems and brought them to the result on the console. If you are not familiar with Java thread 8, see myguide.
InvokeAny
Another way to give back to perform several tasks - method
invokeAny (). It works a little differently: instead of returning Future it blocks the flow before the end at least one task, and returns the result.
To show how this method works, create a method that emulates the behavior of various tasks.He will return
Callable, which will return the specified string after the necessary delay:
Use this method to create multiple tasks with different lines and delays from one to three seconds. Sending these tasks through a method executor
invokeAny () will return the result of problems with the least delay. In this case «task2»:
In the above example we used another type of artists who created a method
newWorkStealingPool () . This method appeared in Java 8, and does not behave like the others: instead of using a fixed number of threads it creates ForkJoinPool a certain parallelism(parallelism size), by default equal to the number of cores of the machine.ForkJoinPool first introduced in Java 7, and we will review it in more detail in the following sections of our management. Now let's look at the performers with a scheduler (scheduledexecutors).Artists with a scheduler
We already know how to give the task executor and get the result. In order to periodically run the task, we can use the thread pool to a scheduler.
ScheduledExecutorService able to run the task once or several times at a specified interval.
This example shows how to get the singer to perform a task after three seconds:
When we pass the task scheduler, it returns a special type of
Future -ScheduledFuture, which provides a method getDelay () for the remaining time before the launch.
Performers with scheduler there are two methods to set the task:
scheduleAtFixedRate () andscheduleWithFixedDelay (). The first set problem with a certain interval, e.g., one second:
In addition, it takes an initial delay, which specifies the time until the first start-up.
Please note that the method
scheduleAtFixedRate () does not take into account the execution of the task. So, if you put a task that is performed for two seconds, at intervals of one, the thread pool will sooner or later overflow.
In this case, you must use the method
scheduleWithFixedDelay (). It works much the same as the previous, but this interval will be counted from the time of completion of the previous task.
In this example we set the task with a delay of one second between the end of the task and the start of the next. The initial delay is not, and each task is performed for two seconds. Thus, the task will start at 0, 3, 6, 9, and so on. G. Second. As you can see, the method
scheduleWithFixedDelay () is very useful when we can not tell in advance how the task will run.
It was the first part of a series of articles about multi-threaded programming. We strongly recommend to dismantle the above examples alone. All are available on GitHub. Feel free forkan repository and add it to the favorites.
I hope you enjoyed the article. If you have any questions, you can ask them in a tweet.
Комментариев нет:
Отправить комментарий