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!