"Java Concurrency in combat," the study notes (1)

Chapter One: Introduction

Knowledge points :

  • Process is resource (CPU, memory, etc.) assigned to the basic unit
  • A thread is the basic unit of CPU scheduling and dispatch
  • A process that includes one or more threads

1, why the application needs to develop from single-threaded to multi-threaded (from synchronous to asynchronous)?

  • Resource utilization . Sometimes it is necessary to wait for external operations, such as input and output, and can not perform valuable work while waiting. While waiting, so that other programs will improve operational efficiency.
  • Fair . Multiple users or programs may have equal priority on system resources. Allow them to share computer time slice through better ways, more desirable than the next program ends after the start of a program.
  • Convenient . Write some procedures, so that they each perform a single task and make the necessary coordination, which is better than writing a program to perform all the tasks easier and more satisfying.

Chapter II: thread-safe

An object's state is its data . Writing thread-safe code, in essence, is the management of the state visit (state), and often are shared , the variable state.

The so-called sharing , refers to a variable can be accessed by multiple threads; the so-called variable refers to the value of the variable can change during its life cycle. Thread safety of our discussion seems to be about the code, but we really need to do, is to protect the data in concurrent access is not controlled.

In the absence of proper synchronization, if multiple threads access the same variable, your program there is risk. There are three ways to fix it:

  • Do not cross-thread shared variables;
  • A state variable is immutable; or
  • Synchronous access at any time state variables.

Thread-safe definition:

When multiple threads access a class, if not consider alternate scheduling and execution in these threads at runtime environment, and does not require additional synchronization and the caller code does not make other coordination behavior of this class is still correct then call this class is thread-safe of.

Stateless objects are always thread-safe.

Thread insecurity complex operation

Read - change - write (read-modify-write)

@NotThreadSafe
public class UnsafeCountingFactorizer implements Servlet {
    private long count = 0;
    public long getCount() { return count; }
    public void service(ServletRequest req, ServletResponse resp) {
        BigInteger i = extractFromRequest(req);
        BigInteger[] factors = factor(i);
        ++count;
        encodeIntoResponse(resp, factors);
    }
}

Check the run (check-act)

@NotThreadsafe
public class LazyInitRace {
    private Expensive0bject instance = null;
    public ExpensiveObject getInstance() {
        if ( instance == null ) {
            instance = new Expensive0bject();
        }
        return instance;
    }
}

In order to ensure thread-safe, "check run" operations (such as lazy initialization) and read - modify - write operations (such as increment) must be atomic. We will "check run" and "Read - change - write" the whole execution process as a complex operation: In order to ensure thread-safe operation must be performed atomically.

In the next section we will consider using Java's built-atomic mechanisms - locks. Now, let's fix this problem in other ways - using the existing thread-safe classes.

@ThreadSafe
public class CountingFactorizer implements Servlet {
    private final AtomicLong count = new AtomicLong(0);
    public long getCount() { return count.get(); }
    public void service(ServletRequest req, ServletResponse resp) {
        BigInteger i = extractFromRequest(req);
        BigInteger[] factors = factor(i);
        count.incrementAndGet();
        encodeIntoResponse(resp, factors);
    }
}

java.util.concurrent.atomicPackage includes variables atoms (atomic variable) classes to implement atomic states of the digital conversion and object references. The longalternative types of counter AtomicLongtypes, we can ensure that all access to counter state are atomic. Counters are thread-safe.

Internal lock

Java provides a built-in lock forced atomic mechanisms: synchronized. A synchronizedblock having two parts: the lock object is referenced, and the lock protection code block.

Each Java object may play a role implicitly lock for synchronization; these built-in locks is called inner lock (intrinsic locks) or a monitor lock (monitor locks).

Execution thread to enter synchronizedand exit through the normal regardless of the control path, or thrown from the block, the threads are to give up; will automatically block until the lock synchronizedis automatically released when the lock control block.

The only way to get inside the lock is: The method of entering the sync block or protect the internal lock.

Internal lock played in Java mutex (mutual exclusion lock, also called a mutex) role, meaning that at most only one thread can own the lock, when the thread A thread is attempting to request a B occupied lock, thread A must wait or block until B releases it. If B never releases the lock, A will wait forever.

Re-entry (Reentrancy)

When a thread requests another thread already has a lock, the requesting thread will be blocked. However, internal lock is re-entered, so that the thread in its own time trying to get possession of the lock, the request will be successful.

Re-entry means that the request is based on " per-thread (per-thread)", rather than on " per call (per-invocation)" is.

It is achieved by reentry to a request count associated with each lock (acquisition count) and a thread owns it. When the count is 0, that the lock is unoccupied.

When a thread requests the lock unoccupied, the JVM recording occupant lock, and the request count is set to 1. If the same thread again requests the lock count is incremented; sync blocks each holding thread exits, the counter value is decremented. Until the counter reaches zero, the lock is released.

/**
*	如果该锁不是可重入的,代码将死锁
*/
public class Widget {
	public synchronized void doSomething() {
		...
	}
}
public class LoggingWidget extends Widget {
	@Override
	public synchronized void doSomething() {
		super.doSomething();
	}
}

For each variable state variable can be accessed by multiple threads, if all the access it has played in the implementation of the thread with a lock, in which case, we call this variable is the lock protection.

Each shared variable variables need to lock protected by only one determined.

Adjust synchronizedthe size of the block, so as to achieve a balance between safety and performance.

Calculation or some time-consuming operations, such as the console or a network I / O, it is difficult to quickly. Do not lock possession during the execution of these operations.

Published 107 original articles · won praise 88 · views 260 000 +

Guess you like

Origin blog.csdn.net/Code_shadow/article/details/104275669