java Multithreaded programming technique details and example code

  • 2020-06-23 00:21:03
  • OfStack

java Multithreaded programming technique details and example code

1. Both Java and his API can use concurrency.

Can specify the program contains different execution threads, each thread has its own way the call stack and the program counter, make the thread in the Shared with other threads can execute concurrently program within the scope of the resources, such as Shared memory, this capability is called multithreaded programming (multithreading), in core C and C + + language does not have this ability, although they have influenced the design of JAVA.

2. The lifetime of the thread

The life cycle of a new thread begins with a "newborn" state. Before the program starts the thread, thread 1 is the "newborn" state. After the program starts the thread, it enters the "runnable" state. A thread in the "runnable" state is considered to be executing its task.

Before the program starts the thread, thread 1 is in the "wait" state and only returns from the "wait" state to the "runnable" state when another thread notifies the waiting thread to continue executing.

A thread in the runnable state can enter the timed wait state, waiting for a specified period of time. The thread returns a runnable state when the time has arrived or when an event that the thread is waiting for occurs. Even if the processor is available, threads in the "timed wait" and "wait" states cannot use it. When a thread in the "runnable" state is waiting for another thread to perform a task, it enters the "timed wait" state if it provides an optional wait period. When another thread notifies the thread, or when a timed time period arrives, whichever is satisfied first, the thread returns to the runnable state. Another way to get a thread into a "timed wait" state is to sleep the thread in the "runnable" state. The sleep thread maintains a "timed wait" for a specified period of time (called a sleep period), after which it returns to a "runnable" state. When a thread has no work to perform, it immediately goes to sleep. ; case
When a thread tries to execute a task, but the task cannot be completed immediately, the thread goes from a runnable state to a blocked state. ; Cases. Even if a processor is available, a thread in the "blocked" state cannot use it.

When the thread completes successfully or terminates (due to an error), the "runnable" thread enters a "terminated" state (sometimes called a "standstill").
At the operating system level, the runnable state of JAVA typically consists of two separate states. When the thread first moves from the "newborn" state to the "runnable" state, the thread is in the "ready" state. When the operating system gives a thread to the processor, it goes from a "ready" state to a "run" state (that is, to start execution), also known as a "scheduled thread." In most operating systems, each thread is given a small processor time (time slice) to perform the task. When the time slice arrives, the thread returns to the "ready" state, and the operating system gives another thread to the processor.

3. Thread priority and thread scheduling

The thread priority range for JAVA is MIN_PRIORITY(constant 1) to MAX_PRIORITY(constant 10), and the default is NORM_PRIORITY(constant 5)

4. Create and execute threads

Create thread recommendations to implement the Runnable interface

(1) Runnable and Thread classes


// Fig. 4.1: PrintTask.java 
 
// PrintTask class sleeps for a random time from 0 to 5 seconds 
 
import java.util.Random; 
 
  
 
public class PrintTask implements Runnable  
 
{ 
 
  private final int sleepTime; // random sleep time for thread 
 
  private final String taskName; // name of task 
 
  private final static Random generator = new Random(); 
 
   
 
  public PrintTask( String name ) 
 
  { 
 
   taskName = name; // set task name 
 
     
 
   // pick random sleep time between 0 and 5 seconds 
 
   sleepTime = generator.nextInt( 5000 ); // milliseconds 
 
  } // end PrintTask constructor 
 
  
 
  // method run contains the code that a thread will execute 
 
  public void run() 
 
  { 
 
   try // put thread to sleep for sleepTime amount of time  
 
   { 
 
     System.out.printf( "%s going to sleep for %d milliseconds.\n",  
 
      taskName, sleepTime ); 
 
     Thread.sleep( sleepTime ); // put thread to sleep 
 
   } // end try     
 
   catch ( InterruptedException exception ) 
 
   { 
 
     System.out.printf( "%s %s\n", taskName, 
 
      "terminated prematurely due to interruption" ); 
 
   } // end catch 
 
     
 
   // print task name 
 
   System.out.printf( "%s done sleeping\n", taskName );  
 
  } // end method run 
 
} // end class PrintTask 

// Fig. 4.2 ThreadCreator.java 
 
// Creating and starting three threads to execute Runnables. 
 
import java.lang.Thread; 
 
  
 
public class ThreadCreator 
 
{ 
 
  public static void main( String[] args ) 
 
  { 
 
   System.out.println( "Creating threads" ); 
 
  
 
   // create each thread with a new targeted runnable 
 
   Thread thread1 = new Thread( new PrintTask( "task1" ) ); 
 
   Thread thread2 = new Thread( new PrintTask( "task2" ) ); 
 
   Thread thread3 = new Thread( new PrintTask( "task3" ) ); 
 
  
 
   System.out.println( "Threads created, starting tasks." ); 
 
  
 
   // start threads and place in runnable state 
 
   thread1.start(); // invokes task1 �  run method 
 
   thread2.start(); // invokes task2 �  run method 
 
   thread3.start(); // invokes task3 �  run method 
 
  
 
   System.out.println( "Tasks started, main ends.\n" ); 
 
  } // end main 
 
} // end class RunnableTester   
 

(2) Thread management and Executor framework

5 creates threads for display, but promotes the use of the Executor interface to manage the execution of Runnable objects. Executor objects create and manage 1 set of threads for Runnable objects, which is the thread pool (thread pool). The advantage of Executor objects is that they can reuse existing threads, reducing the overhead of creating new threads for each task and improving performance.

The Executor interface declares only one method named execute and receives one Runnable argument. Executor assigns each Runnable object passed to its execute method to the available threads in the thread pool. If no thread is available, Executor creates a new thread, or waits for a thread to become available, and assigns the thread to the Runnable object passed to the execute method.

The ExecutorService interface extends the Executor interface.


// Fig. 4.3: TaskExecutor.java 
// Using an ExecutorService to execute Runnables. 
import java.util.concurrent.Executors; 
import java.util.concurrent.ExecutorService; 
 
public class TaskExecutor 
{ 
  public static void main( String[] args ) 
  { 
   // create and name each runnable 
   PrintTask task1 = new PrintTask( "task1" ); 
   PrintTask task2 = new PrintTask( "task2" ); 
   PrintTask task3 = new PrintTask( "task3" ); 
     
   System.out.println( "Starting Executor" ); 
 
   // create ExecutorService to manage threads 
   ExecutorService threadExecutor = Executors.newCachedThreadPool(); 
 
   // start threads and place in runnable state 
   threadExecutor.execute( task1 ); // start task1   
   threadExecutor.execute( task2 ); // start task2 
   threadExecutor.execute( task3 ); // start task3 
 
   // shut down worker threads when their tasks complete 
   threadExecutor.shutdown();  
 
   System.out.println( "Tasks started, main ends.\n" ); 
  } // end main 
} // end class TaskExecutor 

5. Thread synchronization

(1) Thread synchronization (thread synchronization) to coordinate the access of multiple concurrent threads to Shared data. Synchronizing multiple threads in this way ensures that each thread accessing the Shared object can synchronously exclude all other threads, which is called "mutual exclusion."
Another method USES the monitor built into JAVA (monitor). Each object has a monitor and monitor lock (or built-in lock). The monitor ensures that the monitor lock is held by only 11 threads with the highest possible probability at any one time.

(2) Synchronous data sharing: perform atomic operations.


// Adds integers to an array shared with other Runnables 
 
import java.lang.Runnable; 
 
  
 
public class ArrayWriter implements Runnable 
 
{ 
 
  private final SimpleArray sharedSimpleArray; 
 
  private final int startValue; 
 
  
 
  public ArrayWriter( int value, SimpleArray array ) 
 
  { 
 
   startValue = value; 
 
   sharedSimpleArray= array; 
 
  } // end constructor 
 
  
 
  public void run() 
 
  { 
 
   for ( int i = startValue; i < startValue + 3; i++ ) 
 
   { 
 
     sharedSimpleArray.add( i ); // add an element to the shared array 
 
   } // end for 
 
  } // end method run 
 
} // end class ArrayWrite 

// Fig 5.2: SharedArrayTest.java 
 
// Executes two Runnables to add elements to a shared SimpleArray. 
 
import java.util.concurrent.Executors; 
 
import java.util.concurrent.ExecutorService; 
 
import java.util.concurrent.TimeUnit; 
 
  
 
public class SharedArrayTest 
 
{ 
 
  public static void main( String[] arg ) 
 
  { 
 
   // construct the shared object 
 
   SimpleArray sharedSimpleArray = new SimpleArray( 6 ); 
 
  
 
   // create two tasks to write to the shared SimpleArray 
 
   ArrayWriter writer1 = new ArrayWriter( 1, sharedSimpleArray ); 
 
   ArrayWriter writer2 = new ArrayWriter( 11, sharedSimpleArray ); 
 
  
 
   // execute the tasks with an ExecutorService 
 
   ExecutorService executor = Executors.newCachedThreadPool(); 
 
   executor.execute( writer1 ); 
 
   executor.execute( writer2 ); 
 
  
 
   executor.shutdown(); 
 
  
 
   try 
 
   { 
 
     // wait 1 minute for both writers to finish executing 
 
     boolean tasksEnded = executor.awaitTermination(  
 
      1, TimeUnit.MINUTES ); 
 
  
 
     if ( tasksEnded ) 
 
      System.out.println( sharedSimpleArray ); // print contents 
 
     else 
 
      System.out.println(  
 
        "Timed out while waiting for tasks to finish." ); 
 
   } // end try 
 
   catch ( InterruptedException ex ) 
 
   { 
 
     System.out.println(  
 
      "Interrupted while wait for tasks to finish." ); 
 
   } // end catch 
 
  } // end main 
 
} // end class SharedArrayTest 

// Fig.5.3 : SimpleArray.java 
 
// Class that manages an integer array to be shared by multiple  
 
// threads with synchronization. 
 
import java.util.Random; 
 
  
 
public class SimpleArray 
 
{ 
 
  private final int array[]; // the shared integer array 
 
  private int writeIndex = 0; // index of next element to be written 
 
  private final static Random generator = new Random(); 
 
  
 
  // construct a SimpleArray of a given size 
 
  public SimpleArray( int size ) 
 
  { 
 
   array = new int[ size ]; 
 
  } // end constructor 
 
  
 
  // add a value to the shared array 
 
  public synchronized void add( int value ) 
 
  { 
 
   int position = writeIndex; // store the write index 
 
  
 
   try 
 
   { 
 
     // put thread to sleep for 0-499 milliseconds 
 
     Thread.sleep( generator.nextInt( 500 ) );  
 
   } // end try 
 
   catch ( InterruptedException ex ) 
 
   { 
 
     ex.printStackTrace(); 
 
   } // end catch 
 
  
 
   // put value in the appropriate element 
 
   array[ position ] = value; 
 
   System.out.printf( "%s wrote %2d to element %d.\n",  
 
     Thread.currentThread().getName(), value, position ); 
 
  
 
   ++writeIndex; // increment index of element to be written next 
 
   System.out.printf( "Next write index: %d\n", writeIndex ); 
 
  } // end method add 
 
   
 
  // used for outputting the contents of the shared integer array 
 
  public String toString() 
 
  { 
 
   String arrayString = "\nContents of SimpleArray:\n"; 
 
   
 
   for ( int i = 0; i < array.length; i++ ) 
 
     arrayString += array[ i ] + " "; 
 
   
 
   return arrayString; 
 
  } // end method toString 
 
} // end class SimpleArray 
 

Thank you for reading, I hope to help you, thank you for your support to this site!


Related articles: