031. [turn] to see Java multi-thread-safe concurrent state from class

From the state look like multi-threaded Java concurrency safety


For Java developers, i ++ concurrency of insecurity is well known, but it is really so insecure it?

When developing Java code, how to avoid concurrent multi-thread safety issues arise? This is a problem faced by all Java programmers. This article describes the point in the development of Java Code Security concurrent design considerations, the paper with a picture unfold around the Java class status, concurrent discuss security issues in each case. When understand the state variables Java class performance in the concurrent case, when writing multithreaded Java code can be aware of its capability to write more secure, robust and flexible multi-threaded code.

table of Contents

  • 1. Introduction to multithreading
  • 2. From the state look like Java Concurrency security
  • 3. Java security concurrent decomposition
    • 3.1 Stateless class
    • 3.2 stateful class
    • 3.3 Private class status
    • 3.4 share class status
    • 3.5 immutable class state (constant state)
    • 3.6 Variable state class
    • 3.7 Non-blocking design
    • 3.8 blocking design
      • 3.8.1 Resource deadlock (resource deadlock)
      • 3.8.2 Lock sequence deadlock (lock-ordering deadlock)
      • 3.8.3 open state
  • 4. Static state class
  • The external state and class safe concurrent multithreading
  • 6. Summary
  • 7. demo code
  • 8. References

1. Introduction to multithreading

In modern operating system, CPU scheduling are the basic unit of a thread, each thread is independently acquired CPU time slice instruction and executes the code, which is multi-threaded. At the same time, all threads in the same process will be shared memory address space of the current process, these threads can access the same variable on the current memory address space . If a thread when a variable is used, another thread to modify this variable will cause unpredictable results, which is multi-threaded concurrency issues.

A simple example is when an array read cycle of a thread, another thread within the array of objects deleted, then the thread may be in front of a reading or reading failure data is dirty.

In the multi-threaded execution if a piece of code is not properly carried out as expected, or execute unpredictable end result, then we say that this code is complicated by insecurity. In other words, between the threads to execute code if as expected, the result obtained operation data and a desired, safe concurrency is achieved .

2. From the state look like Java Concurrency security

Class status means that variables declared in class, whether public variables, private variables, or that static and final modification of the variables are different forms of class status. According to Java syntax, class variables in various forms as follows,

  • Public variables (public), private variables (private), variable protection (protect)
  • Static variables (static)
  • Immutable variables (Final)
  • External variables, internal variables, local variables

These class variables at runtime, the JVM memory mapped to various objects. Java security concurrent design, the core is how to deal with these variables in the performance of concurrent grasp their characteristics are critical Java security concurrent design.

The following figure departure from class status, a brief description of the various state forms, and related security concurrent Java class variables,

Java security concurrent design

among them,

  • The green boxes illustrate multi-threaded safe.
  • Orange squares illustrate multithreading unsafe, problems will arise.
  • The figure refers to the Java class is entirely based on object-oriented design, namely: class member is declared as private variables, class methods only operate inside the class member variables.
  • There are state refers to Java class has a member variable declarations, whether public, private or protected by variable, or that static and final; no state refers to a class without any member variable declarations.
  • Private status means the class member variables are separated by a thread ThreadLocal, to achieve the allocation of variables by thread; and shared state refers to class variables can be accessed by multiple threads.
  • State is immutable class member variable is declared as final, is a constant state.
  • Static state refers to a class member variable is declared as static.
  • Blocking means if the thread before executing the code, you must obtain a lock, the lock is only one lock achieved by serial multi-threaded code execution.

It should be noted that this figure is based on Java language as an example to illustrate how to design concurrent object class security, but in practice, the state figures involved, private, immutable state, non-blocking and blocking access to these concepts it should apply to more object-oriented programming language.

Figure above description will explain one by one for each class state, introduces complicated design elements in each state.

3. Java security concurrent decomposition

3.1 Stateless class

A stateless class means that it is not a member of any variable declaration , for example,

public class StatelessClass {

    public void increment() { int i = 0; String msg = String.valueOf(i++); log.info(msg); } } 

Stateless class is thread-safe. The above-described class increment () method, there are two local variables i and msg, two local variables are allocated on the stack space method, since the stack memory space by separate threads, isolated from each other, so the stack space the variables are thread-safe.

You can also know the variables and objects allocated in the method call, or if a variable is an object reference JVM release (will not be accessible to the outside again) after the stack exit, then the variables and objects is thread-safe. For more information on local variables and JVM stack space, refer to this article .

3.2 stateful class

Instead stateless and stateful category refers to the class has member variables declared, e.g.

public class StatefulClass {

    private int i=0; public void increment() { i++; } } 

The above class declares a variable int i and initialized to zero. In most cases it belongs to the state of Java classes are classes.

There is a necessary condition for the state lead thread-safe, but it is not a sufficient condition , please read below.

3.3 Private class status

If the status of the Java class ThreadLocal by other methods, such status is isolated in the threads, and interfere with each other, e.g.,

public class PrivateStateClass {

    private ThreadLocal<Integer> i = new ThreadLocal<>(); public void set(int i) { i.set(i); } public void increment() { Integer value = i.get(); i.set(value + 1); } } 

The above class declares a variable ThreadLocal i, this class status were isolated by various threads, as a private state, while performing increment () method can be multi-thread safe access.

3.4 share class status

Normal Java member variables are shared by the threads, multiple threads class method that is provided by Java classes to access an object class, class member variable objects can be shared access to, this is the scenario in most cases.

Shared state in the multi-threaded, is not necessarily unsafe, which in turn can be divided into constant and variable state of the state to discuss the two cases, see below.

3.5 immutable class state (constant state)

The following Java class, there is a Integer PI variable is declared as final, which shows this variable is a constant object does not change after initialization.

public class FinalStateClass {

    private final Integer PI = 3.14; public double calculate(double radius) { return PI*radius*radius; } } 

Multithreaded access above the calculate () method is thread safe.

final declaration makes variable becomes a constant state of multithreading can not change the state during his visit to achieve a read-only to a certain extent, so are thread-safe.

3.6 Variable state class

For variable shared state, when multi-threaded access, there will be co-operation and synchronization problems, if improperly code design, it is very prone to thread insecurity.

For variable shared state visit, it is a major consideration when designing multi-threaded. In order to achieve thread safety, usually by the following two methods,

  • Non-blocking design (multi-threaded parallel execution to achieve thread-safe by the algorithm)
  • Blocking design (lock, so that multithreaded achieve the serial execution)

Here is a brief comparison of these two methods,

  Non-blocking design Blocking design
Multi-threaded execution Parallel execution Serial execution
Security Implementation By algorithm design By Lock
Throughput performance high low
advantage No deadlock, the thread will not be blocked pending Can be achieved by controlled lock thread scheduling
Shortcoming Algorithm complexity, in a highly competitive situation, throughput will be lower than lock Hang threads and context switching, deadlock

A more detailed discussion, see below.

3.7 Non-blocking design

The following Java class AtomicInteger nonblocking self-energizing atoms algorithm variables.

public class AtomicStateClass {

    private AtomicInteger i = new AtomicInteger(0); public void increment() { i.incrementAndGet(); } } 

We can see increment () method does not add any lock, but it can achieve safe increment operator multithreading. The principle is AtomicInteger CAS algorithm, namely compareAndSet () method, first check whether the variables change, if there is no change in the set value, subject to change, then try again, in most instances, set the value at the first attempt They will be successful.

More non-blocking algorithm design, such as non-blocking stack, insert non-blocking list, see here .

3.8 blocking design

Blocking means to control the thread class state by lock access so that only the current state visit by a thread, the thread is suspended waiting for others to access, wait until the lock is released, all waiting threads competing lock, get the next visit right.

Locking design, so that the thread between the respective synchronization, serial execution code instructions, to avoid race conditions. At the same time, however, it also brings a deadlock problems. If the other party needs to hold resources or lock between two threads each other, then enter a deadlock state.

JVM does not provide a better way to resolve the deadlock on the mechanism, more is to provide monitoring tools to view. For the deadlock, the ultimate solution is to rely on developers to implement the code, adding more resources, reduce collisions lock, orderly holds the lock and release from time to time, are effective programs to avoid deadlock.

3.8.1 Resource deadlock (RESOURCE DEADLOCK)

Resource deadlock is a deadlock broad definition, is a simple example, a printer and print job needs to get the file object, if a thread gets the printer, and the other thread to get a file object, not another release resources available, resource deadlock situation occurs.

Adding more resources to solve such deadlock effective program.

3.8.2 Lock sequence deadlock (LOCK-ORDERING DEADLOCK)

The following is a lock deadlock demo code sequence,

public class LockOrderingDeadLock {

    public void transferMoney(Account from, Account to, Integer amount) { synchronized (from) { synchronized (to) { from.debit(amount); to.credit(amount); } } } } 

If two threads started simultaneously, perform the following two operations separately,

  • Thread 1: transferMoney (accountA, accountB, 100)
  • Thread 2: transferMoney (accountB, accountA, 100)

It is likely to deadlock state because the thread 1 at the same time hold accountA object lock, thread 2 also holds accountB lock. The following is a method of testing transferMoney a deadlock situation observed by the JConsole,

Deadlock 2
FIG 1: pool-1-thread-5 holds account @ 120f74e3 lock, lock wait account @ 3e9369b9

Deadlock 1
FIG 2: pool-1-thread-8 holds account @ 3e9369b9 lock, lock wait account @ 120f74e3

One solution is to achieve sequential lock hold that, for any two objects locks A and B, to sort (sorting algorithm must be stable and orderly), regardless of which thread, must be sorted lock, in order to obtain, thus avoiding the need to hold each other's locks.

3.8.3 open state

Refers to a state disclosed class member variable is disclosed, to some extent undermined the data encapsulation in object-oriented design. The method of blocking even the best of the class design, once the state is disclosed, it will fall short of concurrency-safe .

见下面的例子,类中定义了一个personList的对象,方法insert()和iterate()通过synchronized进行了阻塞加锁,其只能运行一个线程进入类方法执行操作。

public class PublicStateClass {

    public ArrayList<String> personList = new ArrayList<>(); public synchronized void insert(String person) { personList.add(person); } public synchronized void iterate() { Integer size = personList.size(); for (int i = 0; i < size; i++) { System.out.println(personList.get(i)); } } } 

但多线程访问insert()和iterate()方法时,并不一定线程安全,主要原因是personList被声明了公开对象,使得类之外的线程可以轻易地访问到personList变量,从而导致personList的状态不一致,在iterate整个person列表时,可能列表中的对象已被删除。

这是类状态公开导致的线程安全问题,究其原因,还要归结于没有做好类的面对对象设计,对外部没有隐藏好数据。

下面的getList方法返回也会导致同样的问题,

public class PublicStateClass {

    private ArrayList<String> personList = new ArrayList<>(); public List getList() { return personList; } } 

对于这样的问题,推荐的做法是,成员变量声明为私有,在执行读操作时,对外克隆一份数据副本,从而保证类内部数据对象不被泄露,

public class PublicStateClass {

    private ArrayList<String> personList = new ArrayList<>(); public List getList() { return (List) personList.clone(); } } 

4. 类的静态状态

类的静态状态是指类中被static声明的成员变量,这个状态会在类初次加载时初始化,被所有的类对象所共享。Java程序员对这个static关键字应该不会陌生,其使用的场景还是非常广泛,比如一些常量数据,由于没有必要在每个Java对象中存储一份,为了节省内存空间,很多时候声明为static变量。

但static变量并发不安全,从面向对象设计来说,一旦变量声明为静态,则作用空间扩大到整个类域,若被声明为公共变量,则成为全局性的变量,static的变量声明大大破坏了类的状态封装。

为了使静态变量变得多线程并发安全,final声明是它的“咖啡伴侣”。在阿里巴巴的编码规范中,其中一条是,若是static成员变量,必须考虑是否为final

5. 类外部状态和多线程安全并发

上文在讲并发设计时,都是针对类内部状态,即类内部成员变量被声明为私有,类方法只对类内部变量进行操作,这是一种简化的应用场景,针对的是依据完全面向对象设计的Java类。一种更常见的情况是,类方法需要对外部传入的对象进行操作。这个时候,类的并发设计则和外部状态息息相关。

例如,

public class StatelessClass {

    public void iterate(List<Person> personList) { Integer size = personList.size(); for (int i = 0; i < size; i++) { System.out.println(personList.get(i)); } } } 

上面的类是一个无状态类,里面没有任何声明的变量。但是iterate方法接受一个personList的列表对象,由外部传入,personList是一个外部状态

外部状态类似上文中内部状态公开,无论在类方法上做如何的参数定义(使用ThreadLocal/final进行声明定义),做如何并发安全措施(加锁,使用非阻塞设计),类方法其对状态的操作都是不安全的。外部状态的安全性取决于外部的并发设计。

一个简单的处理方法,在调用类方法的地方,传入一个外部状态的副本,隔离内外部数据的关联性。

6. 小结

类状态的并发,本质上是内存共享数据对象的多线程访问问题。只有对代码中各个Java对象变量的状态特性掌握透彻,写起并发代码时将事倍功半。

下面的类中,整个hasPosition()方法被synchronized修饰,

public class UserLocator {

    private final Map<String, String> userLocations = new HashMap<>(); public synchronized boolean hasPositioned(String name, String position) { String key = String.format("%s.location", name); String location = userLocations.get(key); return location != null && position.equals(location); } } 

但仔细查看可以知道外部变量name和position、内部变量key和location都是并发安全,只有userLocations这个变量存在并发风险,需要加锁保护。因此,将上面的方法进行如下调整,将减少锁的粒度,有效提高并发效率。

public class UserLocator {

    private final Map<String, String> userLocations = new HashMap<>(); public boolean hasPositioned(String name, String position) { String key = String.format("%s.location", name); String location; synchronized (this) { location = userLocations.get(key); } return location != null && position.equals(location); } } 

由此可见,了解类中各个变量特性对写好并发安全代码的重要性。在这个基础上,优化锁的作用范围,减少锁的粒度,实现锁分段,都可以做到信手拈来,游刃有余。

About class status, he said so much, and finally to a full text of the summary: object-oriented class designed to be hidden good data, good control state class, strictly controlling access to a range of variables, to try private private, can final as much as possible final , these will help to improve the robustness of concurrent code.

7. demo code

All demo code in the following code repository,

8. References

  1. "Java Concurrency in combat." [US] Brian Goetz waiting, Tong Yunlan translated, ISBN: 9787111370048.
  2. IBM DeveloperWorks: non-blocking algorithms Introduction

 

Guess you like

Origin www.cnblogs.com/badboyh2o/p/11072071.html