Clever Geek Handbook
📜 ⬆️ ⬇️

Concurrency in Java

The Java programming language and Java Virtual Machine ( JVM ) are designed to support parallel computing , and all computations are performed in a thread context. Multiple threads can share objects and resources; each thread executes its instructions (code), but potentially can access any object in the program. The responsibilities of the programmer include coordinating (or “ synchronizing ”) the threads during the read and write operations of shared objects. Thread synchronization is needed to ensure that only one thread can access an object at a time, and to prevent threads from accessing incompletely updated objects while another thread is working with them. Java has built-in constructs to support thread synchronization.

Content

Processes and Threads

Most Java virtual machine implementations use a single process to execute a program, and in the Java programming language the concept of parallel computing is most often associated with threads . Threads are sometimes called light processes .

Stream Objects

Threads share process resources, in particular memory and open files. This approach leads to effective but potentially problematic communication. Each application has at least one running thread. The thread from which the program starts is called the main or main . The main thread is able to create additional threads in the form of Runnable or Callable . (The Callable interface Callable similar to Runnable in that they are both designed for classes whose instances will be executed in a separate thread. Runnable , however, does not return a result and cannot throw a checked exception .)

Each thread can be scheduled to run on a separate CPU core, use time quantization on a single-core processor, or use time quantization on multiple processors. In the last two cases, the system will periodically switch between threads, alternately letting one or the other thread execute. Such a scheme is called pseudo-parallelism. There is no universal solution that would say exactly how Java threads will be converted to native OS threads. It depends on the specific implementation of the JVM.

In Java, a thread is represented as a descendant object of the Thread class. This class encapsulates standard flow mechanisms. Streams can be controlled either directly or through abstract mechanisms such as Executor and collections from the java.util.concurrent package.

Start Stream

There are two ways to start a new thread:

  • Implementing the Runnable Interface
  public class HelloRunnable implements Runnable {
     public void run () {
         System  out .  println ( "Hello from the stream!" );
     }
     public static void main ( String [] args ) {
         ( new Thread ( new HelloRunnable ())).  start ();
     }
 }
  • Thread Inheritance
  public class HelloThread extends Thread {
     public void run () {
         System  out .  println ( "Hello from the stream!" );
     }
     public static void main ( String [] args ) {
         ( new HelloThread ()).  start ();
     }
 }

Interrupts

Interruption - an indication to the thread that it should stop the current work and do something else. A thread can send an interrupt by calling the interrupt () method on a Thread object if it is necessary to interrupt the thread associated with it. The interrupt mechanism is implemented using the internal interrupt status flag (interrupt flag) of the Thread class. Calling Thread.interrupt () raises this flag. By convention, any method that throws an InterruptedException throws an interrupt flag. There are two ways to check whether this flag is set. The first way is to call the bool isInterrupted () method of the thread object, the second is to call the static bool Thread.interrupted () method. The first method returns the status of the interrupt flag and leaves this flag intact. The second method returns the state of the flag and discards it. Note that Thread.interrupted () is a static method of the Thread class, and calling it returns the value of the interrupt flag of the thread from which it was called.

Waiting for completion

Java has a mechanism that allows one thread to wait for another thread to complete. To do this, use the Thread.join () method.

Demons

In Java, a process terminates when its last thread ends. Even if the main () method has already completed, but the threads it generated are still executing, the system will wait for them to complete. However, this rule does not apply to a special type of thread - daemons. If the last regular thread of the process is completed, and only daemon threads remain, then they will be forcibly terminated and the process will end. Most often, daemon threads are used to perform background tasks that serve a process throughout its life.

Declaring a stream as a daemon is quite simple - you need to call its setDaemon (true) method before starting the stream; You can check if the stream is a daemon by calling its boolean isDaemon () method.

Exceptions

A thrown and unhandled exception will terminate the thread. The main thread will automatically print the exception to the console, and threads created by the user can do this only by registering the handler. [1] [2]

Memory Model

The Java memory model [1] describes the interaction of threads through memory in the Java programming language. Often on modern computers, for the sake of speed, code is not executed in the order in which it is written. The permutation is performed by the compiler , processor, and memory subsystem . The Java programming language does not guarantee atomicity of operations and consistent consistency when reading or writing fields of shared objects. This solution "unties the hands" of the compiler and allows for optimizations (such as register allocation , removal of general subexpressions and elimination of unnecessary read operations ) based on the permutation of memory access operations. [3]

Sync

Threads communicate by sharing access to the fields and objects referenced by the fields. This form of communication is extremely effective, but makes possible the occurrence of errors of two varieties: interference in the thread (thread interference) and memory consistency errors (memory consistency errors). To prevent their occurrence, there is a synchronization mechanism.

Reordering (reordering) is manifested in incorrectly synchronized multi-threaded programs, where one thread can observe the effects produced by other threads, and such programs may be able to detect that the updated values ​​of variables become visible to other threads in a different order than specified in source code.

To synchronize threads, Java uses monitors , which are a high-level mechanism that allows only one thread to execute a block of code protected by a monitor at a time. The behavior of monitors is considered in terms of locks ; one lock is associated with each object.

Synchronization has several aspects. The most well understood is mutual exclusion - only one thread can own a monitor, so synchronization on a monitor means that as soon as one thread enters a synchronized block protected by a monitor, no other thread can enter a block protected by this monitor until the first thread exits the synchronized block.

But synchronization is more than just a mutual exception. Synchronization ensures that data written to the memory before or inside the synchronized block becomes visible to other streams that are synchronized on the same monitor. After we exit the synchronized block, we release the monitor, which has the effect of flushing the cache into RAM, so that the records made by our stream may be visible to other threads. Before we can enter the synchronized block, we capture the monitor, which has the effect of invalidating the local processor cache so that the variables are loaded from the main memory. Then we can see all the records made by the visible previous release of the monitor. (JSR 133)

A read-write in a field is an atomic operation if the field is declared volatile or is protected by a unique lock obtained before any read-write.

Locks and synchonized blocks

The effect of mutual exclusion and synchronization of threads is achieved by entering a synchronized block or method that implicitly receives a lock, or obtaining a lock explicitly (such as ReentrantLock from the java.util.concurrent.locks package). Both approaches have the same effect on memory behavior. If all attempts to access a certain field are protected by the same lock, then the read-write operations of this field are atomic .

Volatile fields

For fields, the volatile keyword guarantees:

  1. (In all versions of Java) Accesses to the volatile variable are ordered globally. This means that every thread accessing the volatile field will read its value before continuing instead of using the cached value (if possible). (Accesses to volatile variables cannot be reordered with each other, but they can be reordered with accesses to ordinary variables. This negates the usefulness of volatile fields as a means of transmitting a signal from one stream to another.)
  2. (In Java 5 and later) Writing to a volatile field has the same memory effect as releasing a monitor ( English monitor release ), and reading is the same as capturing ( English monitor acquire ). Access to the volatile field establishes the relation “Runs before” ( English happens before ). [4] In essence, this relation is a guarantee that everything that was visible to stream A when it was written in the volatile field f becomes visible to stream B when it reads f .

Volatile fields are atomic. Reading from a volatile field has the same effect as getting a lock: data in the working memory is declared invalid, the value of the volatile field is re-read from memory. Writing to a volatile field has the same memory effect as releasing a lock: a volatile field is immediately written to memory.

Final Fields

A field that is declared final is called final and cannot be changed after initialization. The final fields of an object are initialized in its constructor. If the constructor conforms to certain simple rules, then the correct value of the final field will be visible to other threads without synchronization. A simple rule: the this link must not leave the constructor before it completes.

History

Starting in JDK 1.2 , Java includes a standard set of Java Collections Framework collection classes.

Doug Lee , who also participated in the implementation of the Java Collections Framework, developed the concurrency package , which includes several synchronization primitives and a large number of collection related classes. [5] Work on it was continued as part of JSR 166 [6] under the chairmanship of Doug Lee .

The JDK 5.0 release has included many additions and clarifications to the concurrency model in Java. For the first time, concurrency APIs developed by JSR 166 were included in the JDK. JSR 133 provided support for well-defined atomic operations in a multi-threaded / multi-processor environment.

Both Java SE 6 and Java SE 7 bring changes and additions to the JSR 166 API.

See also

  • Concurrency (computer science)
  • Concurrency Patterns
  • Branching Merge Threads
  • Memory barrier
  • Memory models
  • Streaming security
  • Threadafe

Notes

  1. ↑ Oracle Interface Thread.UncaughtExceptionHandler ( unspecified ) . Date of treatment May 10, 2014.
  2. ↑ Silent Thread death from unhandled exceptions ( unopened ) . literatejava.com . Date of treatment May 10, 2014.
  3. ↑ Herlihy, Maurice, and Nir Shavit. "The art of multiprocessor programming." PODC. Vol. 6.2006.
  4. ↑ Section 17.4.4: Synchronization Order The Java® Language Specification, Java SE 7 Edition (unspecified) . Oracle Corporation (2013). Date of treatment May 12, 2013.
  5. ↑ Doug Lee . Overview of package util.concurrent Release 1.3.4 (unspecified) . - “ Note: Upon release of J2SE 5.0, this package enters maintenance mode: Only essential corrections will be released. J2SE5 package java.util.concurrent includes improved, more efficient, standardized versions of the main components in this package. ". Date of treatment January 1, 2011.
  6. ↑ JSR 166: Concurrency Utilities

Links

  • Goetz, Brian. Java Concurrency in Practice. - Addison Wesley, 2006. - ISBN 0-321-34960-1 .
  • Lea, Doug. Concurrent Programming in Java: Design Principles and Patterns. - Addison Wesley, 1999. - ISBN 0-201-31009-0 .

External links

  • Java Memory Model and Thread Specification simplified Chinese edition
  • Sun / Oracle Java Concurrency tutorial
  • Java Multithreading Steeplechase
  • JDK 5.0 concurrency utilities
  • Podcast from JavaPolis - 'Concurrency Utilities in JDK 5.0 by Brian Goetz'
  • JavaOne 2005 - Concurrency Utilities in Practice
  • JavaOne 2005 - Brian Goetz - Simpler, Faster, Better: Concurrency Utilities in JDK Software Version 5.0
  • Podcast from JavaPosse - Interview with Brian Goetz on Concurrency in Java 5
  • William Pugh's Java Memory Model page
  • Java Concurrency Tutorial by Jakob Jenkov
  • Thread Safe Java Programming by Vadym Ustymenko
  • Java Concurrency Animations by Victor Grazi
  • Thread safety checker for Java classes
  • LiterateJava.com - Silent Thread death from unhandled exceptions
  • Synchronization and Thread Safety in Java
Source - https://ru.wikipedia.org/w/index.php?title=Java&oldid=100033122 Parallelism


More articles:

  • Vidu
  • Grammy Award for Best Album of Modern Christian Music
  • Dimitri (Bekyaris)
  • Faculty of Theology, University of Belgrade
  • Wilson, Lois
  • Maslivets, Olga Viktorovna
  • Astapkovich, Anton Igorevich
  • Cantonese Iron Kung Fu
  • Novotushinskaya Street
  • Shein, Anatoly Borisovich

All articles

Clever Geek | 2019