Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to realize the object sharing of Java concurrent programming

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

This article mainly introduces "how to realize the object sharing of Java concurrent programming". In the daily operation, I believe that many people have doubts about how to realize the object sharing of Java concurrent programming. The editor has consulted all kinds of materials and sorted out simple and easy-to-use operation methods. I hope it will be helpful to answer the doubts of "how to realize the object sharing of Java concurrent programming". Next, please follow the editor to study!

1. Visibility

In general, there is no guarantee that the thread performing the read operation will see the values written by other threads, because each thread has its own caching mechanism. To ensure visibility of memory writes between multiple threads, a synchronization mechanism must be used.

Public class NoVisibility {private static boolean ready; private static int number; private static class ReaderThread extends Thread {public void run () {while (! ready) Thread.yield (); System.out.println (number);}} public static void main (String [] args) {new ReaderThread () .start (); number = 42; ready = true }}

The above code looks like it will output 42, but in fact it will probably not be terminated at all, because the reader thread will never see the value of ready; it will most likely output 0, because the reader thread will see the value written to ready but not the value written to number later, a phenomenon called "reordering". In the absence of synchronization, compilers, processors, runtimes, and so on, may make some unexpected adjustments to the order in which operations are performed.

Therefore, as long as there is data to be shared between multiple threads, correct synchronization should be used.

1.1 failure data

Unless synchronization is used, it is likely to get the invalidation value of the variable. The invalid value may not occur at the same time, and one thread may get the latest value of one variable and the invalid value of another variable. Failure data can also lead to some confusing failures, such as unexpected exceptions, broken data structures, imprecise calculations, infinite loops, and so on.

1.2 non-atomic 64-bit operation

For non-volatile types of long and double variables, JVM allows 64-bit read or write operations to be broken down into two 32-bit operations. Therefore, it is likely to read a high 32-bit value of the latest value and a low 32-bit value of the invalid value, causing the read to be a random value. Unless you declare them with the keyword volatile, or protect them with a lock.

1.3 locking and visibility

When a thread executes a block of synchronous code protected by a lock, you can see the results of all previous operations of other threads in the same block of synchronous code. If there is no synchronization, the above guarantee cannot be achieved. The meaning of locking is not limited to mutually exclusive behavior, but also to visibility. To ensure that all threads can see the latest values of shared variables, all threads performing read or write operations must be synchronized on the same lock.

1.4 volatile variable

When a variable is declared to be of type volatile, neither the compiler nor the runtime will reorder the operations on the variable as well as other memory operations. Volatile variables are not cached where registers or other processors are not visible, so the most recently written value is always returned when the volatile variable is read. The locking mechanism ensures both visibility and atomicity, while the volatile variable only ensures visibility.

The volatile variable should be used only if and only if all of the following conditions are met:

Writing to a variable does not depend on the current value of the variable, or ensures that only a single thread is used to update the value of the variable.

This variable is not included in the invariance condition along with other state variables.

There is no need to lock variables when accessing them.

two。 Release and disclosure

Publishing an object means that the object can be used in code outside the current scope. The ways to publish objects include references to non-private variables, references returned by method calls, references to inner class objects implying references to external classes, and so on. When an object that should not be published is published, it is called a leak.

Public class ThisEscape {private int status; public ThisEscape (EventSource source) {source.registerListener (new EventListener () {public void onEvent (Event e) {doSomething (e);}}); status = 1;} void doSomething (Event e) {status = e.getStatus ();} interface EventSource {void registerListener (EventListener e);} interface EventListener {void onEvent (Event e) } interface Event {int getStatus ();}}

Because instances of inner classes contain implicit references to instances of external classes, when ThisEscape publishes EventListener, it also implicitly publishes the ThisEscape instance itself. At this point, however, the variable status has not been initialized, causing the this reference to be leaked in the constructor. You can use a private constructor and a public factory method to avoid incorrect construction processes:

Public class SafeListener {private int status; private final EventListener listener; private SafeListener () {listener = new EventListener () {public void onEvent (Event e) {doSomething (e);}}; status = 1;} public static SafeListener newInstance (EventSource source) {SafeListener safe = new SafeListener (); source.registerListener (safe.listener) Return safe;} void doSomething (Event e) {status = e.getStatus ();} interface EventSource {void registerListener (EventListener e);} interface EventListener {void onEvent (Event e);} interface Event {int getStatus ();}} 3. Thread closure

One way to avoid using synchronization is not to share. If you only access data within a single thread, synchronization is not required, which is called thread closure. Thread closure is a consideration in programming and must be implemented in the program. Java also provides mechanisms to help maintain thread closure, such as local variables and ThreadLocal.

3.1 Ad-hoc thread closure

Ad-hoc thread closure means that the responsibility of maintaining thread closure is entirely borne by the program implementation. Using volatile variables is a way to achieve Ad-hoc thread closure. As long as only a single thread is guaranteed to write to shared volatile variables, read-modify-write operations can be performed safely on these variables, and the visibility of volatile variables ensures that other threads can see the latest values.

Ad-hoc thread closure is very fragile, so it is used as little as possible in programs. Where possible, use other thread closure techniques, such as stack closure, ThreadLocal.

3.2 Stack closure

In stack closure, objects can only be accessed through local variables. They are on the stack of the executing thread and cannot be accessed by other threads. Even if these objects are non-thread-safe, they are still thread-safe. It is worth noting, however, that only the code writer knows which objects are stack-closed. If it is not clearly stated, it is easy for subsequent maintenance personnel to mistakenly disclose these objects.

3.3CLA ThreadLocal

Using ThreadLocal is a more standardized form of thread closure, which can associate a value in the thread with the object that holds the value. In the following code, each thread has its own connection by saving the JDBC connection to the ThreadLocal object:

Public class ConnectionDispenser {static String DB_URL = "jdbc:mysql://localhost/mydatabase"; private ThreadLocal connectionHolder = new ThreadLocal () {public Connection initialValue () {try {return DriverManager.getConnection (DB_URL);} catch (SQLException e) {throw new RuntimeException ("Unable to acquire Connection, e") }; public Connection getConnection () {return connectionHolder.get ();}}

Conceptually, you can think of ThreadLocal as containing a Map object that holds thread-specific values, but this is not the case with the implementation of ThreadLocal. These thread-specific values are stored in the Thread object and are collected as garbage when the thread terminates.

4. Invariance

If the state of an object cannot be modified after it is created, the object is called an immutable object. Another way to meet synchronization requirements is to use immutable objects. Immutable objects must be thread-safe. The object is immutable when the following conditions are met:

The state of an object cannot be changed after it is created

All fields of the object are of type final

The object is created correctly, and the this reference is not leaked during object creation

Public final class ThreeStooges {private final Set stooges = new HashSet (); public ThreeStooges () {stooges.add ("Moe"); stooges.add ("Larry"); stooges.add ("Curly");} public boolean isStooge (String name) {return stooges.contains (name);}}

In the above code, although the stooges object is mutable, it cannot be modified after it has been constructed. Stooges is a reference variable of type final, so all object states are accessed through a find domain. In the constructor, the this reference cannot be accessed by code other than the constructor.

4.1 final domain

Fields of type final cannot be modified, but if the objects referenced by the final domain are mutable, then the referenced objects can be modified. Objects in the final domain are not reordered in the constructor, so the find domain also ensures the security of the initialization process. Like "all domains should be declared as private domains unless greater visibility is required," it is also a good programming practice to declare a domain as a finaldomain unless it needs to be mutable.

4.2 publish immutable objects using volatile types

Factoring Sevlet performs two atomic operations:

Update cach

Determine whether to read the result in the cache directly by determining whether the value in the cache is equal to the requested value.

Whenever you need a set of related data to perform an operation atomically, consider creating an immutable class to contain the data:

Public class OneValueCache {private final BigInteger lastNumber; private final BigInteger [] lastFactors; public OneValueCache (BigInteger I, BigInteger [] factors) {lastNumber = I; lastFactors = Arrays.copyOf (factors, factors.length);} public BigInteger [] getFactors (BigInteger I) {if (lastNumber = = null | |! lastNumber.equals (I)) return null; else return Arrays.copyOf (lastFactors, lastFactors.length);}}

When a thread gets a reference to an immutable object, you don't have to worry that another thread will modify the state of the object. If you want to update these variables, you can create a new container object, but other threads that use the original object will still see the object in a consistent state. When a thread sets a cache of type volatile to reference a new OneValueCache, other threads immediately see the newly cached data:

Public class VolatileCachedFactorizer implements Servlet {private volatile OneValueCache cache = new OneValueCache (null, null); public void service (ServletRequest req, ServletResponse resp) {BigInteger I = extractFromRequest (req); BigInteger [] factors = cache.getFactors (I); if (factors = = null) {factors = factor (I); cache = new OneValueCache (I, factors);} encodeIntoResponse (resp, factors) }} 5 Security release 5.1 incorrect release

It is not safe to save object references to the public domain like this:

Public Holder holder;public void initialize () {holder = new Holder (42);}

Due to visibility issues, Holder objects seen by other threads will be in an inconsistent state. Except for the thread that published the object, other threads can see that the Holder field is an invalid value, so they will see a null reference or the previous old value.

Public class Holder {private int n; public Holder (int n) {this.n = n;} public void assertSanity () {if (n! = n) throw new AssertionError ("This statement is false.");}

In the above code, assertSanity may throw an AssertionError even if the Holder object is published correctly. Because the thread sees that the value referenced by Holder is up-to-date, but because the value of the reordered Holder state is timed.

5.2 immutable objects and initialization security

Even if synchronization is not used when publishing a reference to an immutable object, the object can still be safely accessed. Any thread can safely access immutable objects without additional synchronization, even if synchronization is not used when publishing those objects. You can also securely access domains of type final without additional synchronization. However, if fields of type final point to mutable objects, synchronization is still needed when accessing the state of the objects that those fields point to.

5.3 Common modes for secure publishing

To safely publish an object, the reference to the object and its state must be visible to other threads at the same time. A properly constructed object can be safely published in the following ways:

Initialize an object reference in a static initialization function.

Save a reference to an object to a domain of type volatile or an AtomicReference object.

Save a reference to the object to the final type field of some correctly constructed object.

Saves a reference to an object to a domain protected by a lock.

The container classes in the thread-safe library provide the following secure release guarantees:

By placing a key or value in a Hashtable, synchronizedMap, or ConcurrentMap, you can safely publish it to any thread that accesses it from these containers.

By placing an object in Vector, CopyOnWriteArrayList, CopyOnWriteArraySet, synchronizedList, or synchronizedSet, you can safely publish the object to any thread that accesses the object from those containers.

By placing an object in a BlockingQueue or ConcurrentLinkedQueue, you can safely publish the object to any thread that accesses the object from these queues.

5.4 fact immutable object

An object is called an immutable object if it is technically mutable but its state does not change after release. Any thread can safely use a de facto immutable object that is safely published without additional synchronization. For example, maintain a Map object that holds the latest login time for each user:

Public Map lastLogin =

Collections.synchronizedMap (new HashMap

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report