"The Art of Java Concurrent Programming" "Learning Notes" threadlocal and fork/join__ algorithms

Source: Internet
Author: User
Tags exception handling static class throwable
5. Other 5.1, ThreadLocal

A solution to the problem of member variables in a multithreaded environment, but it has nothing to do with thread synchronization. The idea is to create a separate copy of the variable for each thread, so that each thread can independently change its own copy of the variable without affecting the corresponding copy of the other thread.

Threadlocal is not intended to solve the problem of shared variables, nor to reconcile thread synchronization, but to introduce a mechanism to facilitate each thread to handle its own state.

Four methods of threadlocal:

Get (): Returns the value in the current thread copy of this thread local variable.

InitialValue (): Returns the "initial value" of the current thread for this thread local variable.

Remove (): Removes the value of the current thread for this thread local variable.

Set (T value): Sets the value in the current thread copy of this thread local variable to the specified value.

Get Method:

The public T get () {
  thread t = thread.currentthread ();//Gets the current thread
  threadlocalmap map = Getmap (T); Returns t.threadlocals, the local variable threadlocalmap
  if (map!= null) {//When the current thread has threadlocalmap
    threadlocalmap.entry e = Map.getentry (this); the entry,key from the current thread to get the map is Threadlocal,value is the value
    if (e!= null) {
      @SuppressWarnings (" Unchecked ")
      T result = (t) e.value;
      return result;
    }
  return Setinitialvalue ();
}

Static Class Entry extends Weakreference<threadlocal<?>> {
  /** the value associated with this Threadloca L. *
  /Object value;
  Entry (threadlocal<?> K, Object v) {
    super (k);
    Value = V;
  }
}
Initialize Threadlocalmap and Entry
private T Setinitialvalue () {
  T value = InitialValue ();
  Thread t = thread.currentthread ();
  Threadlocalmap map = getmap (t);
  if (map!= null)
    Map.set (this, value);
  else
    createmap (t, value);
  return value;
}

InitialValue Method:

Protected T InitialValue () {//new threadlocal initialization of return
  null;
}

Remove Method:

public void Remove () {
  Threadlocalmap m = Getmap (Thread.CurrentThread ());
  if (M!= null)
    m.remove (this);//this is the current ThreadLocal
}
private void Remove (threadlocal<?> key) {
  entry[] tab = table;
  int len = tab.length;
  int i = Key.threadlocalhashcode & (len-1); The subscript for
  (Entry e = tab[i] after the hash;
       e!= null;
       E = Tab[i = Nextindex (i, Len)]) {
    if (e.get () = = key) {
      e.clear ();
      Expungestaleentry (i); Clear stale entry return
      }}

set (T value) method:

public void Set (t value) {
  Thread t = thread.currentthread ();
  Threadlocalmap map = getmap (t);
  if (map!= null)
    Map.set (this, value);
  else
    createmap (t, value);
void Createmap (Thread T, T firstvalue) {
  t.threadlocals = new Threadlocalmap (this, firstvalue);

Threadlocalmap

Threadlocalmap is the key to implementing the thread isolation mechanism .

Inside each thread, there is a THREADLOCAL.THREADLOCALMAP type member variable that stores the actual copy of the threadlocal variable.
As you can see from the Get method, the T.threadlocals = new Threadlocalmap (this, firstvalue) is executed if there is no threadlocalmap in the current thread;.

Threadlocalmap provides a method for storing a copy of a variable of each thread using a key-value pair method, the key is the current Threadlocal object, and the value is a variable copy of the corresponding thread.

pay attention.

The THREADLOACL instance itself does not store a value, it simply provides a key that finds a replica value in the current thread.

Threadlocal is included in thread, not thread is contained in threadlocal.

Memory leak problem

Threadlocalmap,key Weak reference ,value Strong reference , cannot be recycled. The entry object is constructed using threadlocal and values in the Threadlocalmap set method. The static class Entry extends weakreference<threadlocal<?>> the object's key (that is, ThreadLocal) is a weak reference. (If an object has a weak reference, the memory is reclaimed when the GC thread scans the memory area, regardless of whether the current memory space is sufficient or not.) , each key is a weak reference point to threadlocal.
When the threadlocal instance is null, no strong references point to the threadlocal instance, so threadlocal will be reclaimed by GC. The value of the key, however, cannot be recycled because value in entry is a strong reference to the instance. The current thread does not exist on the stack until the current threads end, and the strong reference is disconnected when the current Thread,map,value back is all collected by GC.

WORKAROUND: Show call Remove (). 5.2, Fork/join

The Fork/join framework is a framework that JAVA7 provides for the parallel execution of tasks, a framework that divides the big shots into small tasks, eventually aggregating the results of each small task.
The core idea is "divide and conquer", fork decomposition task, join collection task.

work-Stealing algorithms
A work-stealing algorithm is a thread that steals tasks from other queues to execute.
Executing fast threads steals tasks from other thread queues to perform, helping slow thread execution tasks and improving the efficiency of the entire task.
By using bidirectional queues, the thread of the stolen task is always taken from the head of the queue, and the thread that steals the task is taken from the tail of the queue.
The Advantage is to make full use of threads for concurrent computation and reduce competition between threads. The disadvantage is that in some cases there is competition, such as when there is only one task in the two-terminal queue, and the algorithm consumes more system resources, such as creating more threads and bidirectional queues.

Core class
Forkjoinpool task thread pool
Forkjointask identity task, for forkjoinpool tasks abstract
Forkjoinworkerthread the worker thread that executes the task

public class Counttask extends recursivetask<integer> {private static final int THRESHOLD = 2;//threshold Private
    int start;

    private int end;
        Public counttask (int start, int end) {This.start = start;
    This.end = end;
        @Override protected Integer Compute () {int sum = 0;
        If the task is small enough, compute the task Boolean cancompute = (end-start) <= THRESHOLD;
            if (Cancompute) {for (int i = start; I <= end; i++) {sum = i;
            } else {//If the task is greater than the threshold, split into two subtasks to compute int middle = (start + end)/2;
            Counttask lefttask = new Counttask (start, middle);
            Counttask righttask = new Counttask (middle + 1, end);
            Perform subtask lefttask.fork ();
        Righttask.fork ();
            Wait for subtasks to finish and get their results int leftresult = Lefttask.join ();
            int rightresult = Righttask.join (); Merge subtasks sum = LeftrEsult + Rightresult;
    return sum;
        public static void Main (string[] args) {Forkjoinpool forkjoinpool = new Forkjoinpool ();
        Generates a computational task that calculates 1+2+3+4 counttask task = new Counttask (1, 4);
        Perform a task future<integer> result = Forkjoinpool.submit (Task);
        try {System.out.println (Result.get ()); catch (Interruptedexception e) {} catch (Executionexception e) {}}}

Exception Handling
Forkjointask may throw an exception while executing, but we have no way to catch the exception directly in the main thread, so Forkjointask provides a iscompletedabnormally () method to check whether the task has thrown an exception or has been canceled. And you can get the exception through the Forkjointask GetException method.

if (task.iscompletedabnormally ()) {
  System.out.println (task.getexception ());
}

Implementation Principle
The Forkjoinpool is composed of a forkjointask array and a forkjoinworkerthread array, and the Forkjointask array is responsible for the tasks that are submitted to the Forkjoinpool by the hosting program. The Forkjoinworkerthread array is responsible for performing these tasks.
(1) Principle of Forkjointask fork method
When we call the Forkjointask fork method, the program invokes the Forkjoinworkerthread Pushtask method
Perform this task asynchronously, and then return the result immediately:

Public final forkjointask<v> Fork () {(
  forkjoinworkerthread) Thread.CurrentThread ()). Pushtask (this);
  return this;
}

The Pushtask method stores the current task in the Forkjointask array queue. And then call Forkjoinpool's
The Signalwork () method wakes up or creates a worker thread to perform the task.

final void Pushtask (Forkjointask<> t) {
  forkjointask<>[] q; int s, M;
  if ((q = queue)!= null) {//Ignore if queue removed
    long u = (((s = queuetop) & (M = q.length-1)) << Ashift) + abase;
    Unsafe.putorderedobject (q, U, t);
    Queuetop = s + 1; or use Putorderedint
    if ((S-= queuebase) <= 2)
      pool.signalwork ();
    else if (s = = m)
      growqueue ();
  }

(2) Implementation principle of Forkjointask join method

The main function of the join method is to block the current thread and wait for the result to be obtained.

Public final V join () {
  if (Dojoin ()!= NORMAL) return
    reportresult ();
  else return
    Getrawresult ();
} 
Private Vreportresult () {
  int s; Throwable ex;
  if ((s = status) = = cancelled)
    throw new Cancellationexception ();
  if (s = = Exceptional && (ex = Getthrowableexception ())!= null)
    unsafe.throwexception (ex);
  return Getrawresult ();
}

First, it calls the Dojoin () method, and obtains the status of the current task through the Dojoin () method to determine what knot to return
There are 4 types of task states: Completed (NORMAL), canceled (cancelled), signal (SIGNAL), and unexpected
(exceptional). If the task status is completed, the task results are returned directly. • Throw cancellationexception If the task status is canceled. • If the task status is to throw an exception, the corresponding exception is thrown directly.

private int Dojoin () {
  Thread t; Forkjoinworkerthread W; int s; Boolean completed;
  if (t = Thread.CurrentThread ()) instanceof Forkjoinworkerthread) {
    if ((s = status) < 0) return
      s;
    if (w = (forkjoinworkerthread) t). Unpushtask (This)) {
      try {
        completed = exec ();
      } catch (Throwable Rex) {
  
   return Setexceptionalcompletion (Rex);
      if (completed) return
        setcompletion (NORMAL);
    }
    Return W.jointask (this);
  }
  else return
    Externalawaitdone ();
}
  

In the Dojoin () method, first by looking at the status of the task, see if the task has been completed, and if the execution is completed,
Returns the task status directly or, if not, the task is fetched from the task array and executed. If the task is executed smoothly
Completes, set the task status to normal and, if an exception occurs, log the exception and set the task status to
Exceptional.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.