java多线程编程技术详解和实例代码

 java多线程编程技术详解和实例代码

1.   Java和他的API都可以使用并发。

可以指定程序包含不同的执行线程,每个线程都具有自己的方法调用堆栈和程序计数器,使得线程在与其他线程并发地执行能够共享程序范围内的资源,比如共享内存,这种能力被称为多线程编程(multithreading),在核心的C和C++语言中并不具备这种能力,尽管他们影响了JAVA的设计。

2.   线程的生命周期

新线程的生命周期从“新生”状态开始。程序启动线程前,线程一直是“新生”状态;程序启动线程后,线程进入“可运行”状态。“可运行”状态的线程,被认为是正在执行他的任务。

在程序启动线程之前,线程一直处于“等待”状态,只有当另一个线程通知正在等待的线程继续执行时,这个线程才会从“等待”状态恢复到“可运行”状态。

“可运行”状态的线程可以进入“定时等待”状态,等待一个指定的时间段。当时间到达或线程正在等待的某个事件发生时,该线程就会返回“可运行”状态。即使处理器可以使用,处于“定时等待”状态和“等待”状态的线程也不能用它。当处于“可运行”状态的线程正在等待另一个线程执行任务时,如果它提供了可选的等待时间段,则这个线程会进入“定时等待”状态。当另一个线程通知了这个线程,或者当定时的时间段到达时(以先满足的为准),这个线程就会返回到“可运行”状态.。使线程进入“定时等待”状态的另一方法是是处于“可运行”状态的线程睡眠。睡眠线程会在“定时等待”状态维持一个指定的时间段(称为睡眠时间段),过了这段时间,它会返回到“可运行”状态。当线程没有工作要执行时,它会立即睡眠。;例
当线程试图执行某个任务,而任务又不能立即完成,线程就从“可运行”状态转到“阻塞”状态。;例。即使有处理器可供使用,“阻塞”状态的线程也不能使用它。

线程成功完成任务,或者(由于出错)终止了时,“可运行”线程就会进入“终止”状态(有时称“停滞”状态)。
在操作系统级别,JAVA的“可运行”状态通常包含两个独立的状态。当线程首先从“新生”状态转到“可运行”状态,线程处于“就绪”状态。当操作系统将线程给处理器时,线程就从“就绪”状态进入“运行”状态(即开始执行),这也被称为“调度线程”。大多数操作系统中,每个线程被赋予一小段处理器时间(时间片)来执行任务。当时间片到达时,线程就会返回到“就绪”状态,而操作系统将另一个线程给予处理器。

3.   线程优先级与线程调度

JAVA的线程优先级范围为MIN_PRIORITY(常量1)到MAX_PRIORITY(常量10),默认是NORM_PRIORITY(常量5)

4.   创建并执行线程

创建线程推介实现Runnable接口

(1)Runnable与Thread类

// 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)线程管理与Executor框架

5为显示的创建线程,但推介使用Executor接口,用来管理Runnable对象的执行。Executor对象创建并管理一组Runnable对象的线程,这组线程就做线程池(thread pool).优点是Executor对象能复用了已经有的线程,减少为每个任务创建新线程的开销,提高性能。

Executor接口只声明了一个名称为execute的方法,接收一个Runnable实参。Executor会将传递给他的execute方法的每个Runnable对象赋予线程池中可以用的线程。如果没有可以用的线程,则Executor会创建一个新线程,或等待某个线程会成为可用的,并会将这个线程赋予传递给execute方法的Runnable对象。

ExecutorService接口扩展了Executor接口。

// 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.       线程同步 

(1)线程同步(thread synchronization),协调多个并发线程对共享数据的访问。这种方式同步多个线程,就可以保证访问共享对象的每个线程都能同步地将其他所有线程排除在外,这被称为“互斥”。
另一个方法,使用JAVA内置的监控器(monitor)。每个对象都有一个监控器和监控锁(或内置锁)。监控器保证任何时候监控锁由具有最大可能的唯一一个线程持有。

(2)同步的数据共享:执行原子操作。

// 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 

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

时间: 2017-04-13

详解Java多线程编程中互斥锁ReentrantLock类的用法

0.关于互斥锁 所谓互斥锁, 指的是一次最多只能有一个线程持有的锁. 在jdk1.5之前, 我们通常使用synchronized机制控制多个线程对共享资源的访问. 而现在, Lock提供了比synchronized机制更广泛的锁定操作, Lock和synchronized机制的主要区别: synchronized机制提供了对与每个对象相关的隐式监视器锁的访问, 并强制所有锁获取和释放均要出现在一个块结构中, 当获取了多个锁时, 它们必须以相反的顺序释放. synchronized机制对锁的释放是

java多线程编程制作电子时钟

模拟一个电子时钟,它可以在任何时候被启动或者停止,并可以独立的运行. 1.定义一个Clock类.它继承Label类,并实现Runnable接口.这个类中有一个Thread类型的clocker域,以及start()和run()方法.在run()方法中,每隔一秒就把系统时间显示为label的文本. class Clock extends Label implements Runnable { //定义Thread类型的clocker域 public Thread clocker=null; publ

java多线程编程之为什么要进行数据同步

Java中的变量分为两类:局部变量和类变量.局部变量是指在方法内定义的变量,如在run方法中定义的变量.对于这些变量来说,并不存在线程之间共享的问题.因此,它们不需要进行数据同步.类变量是在类中定义的变量,作用域是整个类.这类变量可以被多个线程共享.因此,我们需要对这类变量进行数据同步.数据同步就是指在同一时间,只能由一个线程来访问被同步的类变量,当前线程访问完这些变量后,其他线程才能继续访问.这里说的访问是指有写操作的访问,如果所有访问类变量的线程都是读操作,一般是不需要数据同步的.那么如果不

Java多线程编程之访问共享对象和数据的方法

多个线程访问共享对象和数据的方式有两种情况: 1.每个线程执行的代码相同,例如,卖票:多个窗口同时卖这100张票,这100张票需要多个线程共享. 2.每个线程执行的代码不同,例如:设计四个线程,其中两个线程每次对j增加1,另外两个线程每次对j减少1. a.如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个对象中有共享数据.卖票就可以这样做,每个窗口都在做卖票任务,卖的票都是同一个数据(点击查看具体案例). b.如果每个线程执行的代码不同,就需要使用不同的Runnable对象,有

Java多线程编程中的两种常用并发容器讲解

ConcurrentHashMap并发容器 ConcurrentHashMap可以做到读取数据不加锁,并且其内部的结构可以让其在进行写操作的时候能够将锁的粒度保持地尽量地小,不用对整个ConcurrentHashMap加锁. ConcurrentHashMap的内部结构 ConcurrentHashMap为了提高本身的并发能力,在内部采用了一个叫做Segment的结构,一个Segment其实就是一个类Hash Table的结构,Segment内部维护了一个链表数组,我们用下面这一幅图来看下Con

java多线程编程之使用Synchronized块同步变量

下面的代码演示了如何同步特定的类方法: 复制代码 代码如下: package mythread; public class SyncThread extends Thread{ private static String sync = ""; private String methodType = ""; private static void method(String s) {  synchronized (sync)  {sync = s;System.out

Java多线程编程之读写锁ReadWriteLock用法实例

读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的,你只要上好相应的锁即可.如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁:如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁.总之,读的时候上读锁,写的时候上写锁! 三个线程读数据,三个线程写数据示例: 可以同时读,读的时候不能写,不能同时写,写的时候不能读. 读的时候上读锁,读完解锁:写的时候上写锁,写完解锁. 注意finally解锁. package com.ljq.test.th

详解Java多线程编程中CountDownLatch阻塞线程的方法

直译过来就是倒计数(CountDown)门闩(Latch).倒计数不用说,门闩的意思顾名思义就是阻止前进.在这里就是指 CountDownLatch.await() 方法在倒计数为0之前会阻塞当前线程. CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待. CountDownLatch 的作用和 Thread.join() 方法类似,可用于一组线程和另外一组线程的协作.例如,主线程在做一项工作之前需要一系列的准备工作,只有这些准备工

java的多线程用法编程总结

一.进程与线程 1.进程是什么? 狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed). 广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动.它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元. 2.线程是什么? 线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元.一个标准的线程由线

Java 多线程并发编程_动力节点Java学院整理

一.多线程 1.操作系统有两个容易混淆的概念,进程和线程. 进程:一个计算机程序的运行实例,包含了需要执行的指令:有自己的独立地址空间,包含程序内容和数据:不同进程的地址空间是互相隔离的:进程拥有各种资源和状态信息,包括打开的文件.子进程和信号处理. 线程:表示程序的执行流程,是CPU调度执行的基本单位:线程有自己的程序计数器.寄存器.堆栈和帧.同一进程中的线程共用相同的地址空间,同时共享进进程锁拥有的内存和其他资源. 2.Java标准库提供了进程和线程相关的API,进程主要包括表示进程的jav

Java多线程并发编程 Volatile关键字

volatile 关键字是一个神秘的关键字,也许在 J2EE 上的 JAVA 程序员会了解多一点,但在 Android 上的 JAVA 程序员大多不了解这个关键字.只要稍了解不当就好容易导致一些并发上的错误发生,例如好多人把 volatile 理解成变量的锁.(并不是) volatile 的特性: 具备可见性 保证不同线程对被 volatile 修饰的变量的可见性. 有一被 volatile 修饰的变量 i,在一个线程中修改了此变量 i,对于其他线程来说 i 的修改是立即可见的. 如: vola

Java多线程并发编程(互斥锁Reentrant Lock)

Java 中的锁通常分为两种: 通过关键字 synchronized 获取的锁,我们称为同步锁,上一篇有介绍到:Java 多线程并发编程 Synchronized 关键字. java.util.concurrent(JUC)包里的锁,如通过继承接口 Lock 而实现的 ReentrantLock(互斥锁),继承 ReadWriteLock 实现的 ReentrantReadWriteLock(读写锁). 本篇主要介绍 ReentrantLock(互斥锁). ReentrantLock(互斥锁)

Java Thread多线程详解及用法解析

最全面的java多线程用法解析,如果你对Java的多线程机制并没有深入的研究,那么本文可以帮助你更透彻地理解Java多线程的原理以及使用方法. 1.创建线程 在Java中创建线程有两种方法:使用Thread类和使用Runnable接口.在使用Runnable接口时需要建立一个Thread实例.因此,无论是通过Thread类还是Runnable接口建立线程,都必须建立Thread类或它的子类的实例.Thread构造函数: public Thread( ); public Thread(Runnab

Java多线程用法的实例详解

Java多线程用法的实例详解 前言: 最全面的java多线程用法解析,如果你对Java的多线程机制并没有深入的研究,那么本文可以帮助你更透彻地理解Java多线程的原理以及使用方法. 1.创建线程 在Java中创建线程有两种方法:使用Thread类和使用Runnable接口.在使用Runnable接口时需要建立一个Thread实例.因此,无论是通过Thread类还是Runnable接口建立线程,都必须建立Thread类或它的子类的实例.Thread构造函数: public Thread( ); p

Java多线程并发编程和锁原理解析

这篇文章主要介绍了Java多线程并发编程和锁原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.前言 最近项目遇到多线程并发的情景(并发抢单&恢复库存并行),代码在正常情况下运行没有什么问题,在高并发压测下会出现:库存超发/总库存与sku库存对不上等各种问题. 在运用了 限流/加锁等方案后,问题得到解决. 加锁方案见下文. 二.乐观锁 & 悲观锁 1.乐观锁 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁

Java RandomAccessFile的用法详解

RandomAccessFile RandomAccessFile是用来访问那些保存数据记录的文件的,你就可以用seek( )方法来访问记录,并进行读写了.这些记录的大小不必相同:但是其大小和位置必须是可知的.但是该类仅限于操作文件. RandomAccessFile不属于InputStream和OutputStream类系的.实际上,除了实现DataInput和 DataOutput接口之外(DataInputStream和DataOutputStream也实现了这两个接口),它和这两个类系毫

java.text.DecimalFormat用法详解

简要 DecimalFormat 的 pattern 都包含着 正负子 pattern ,例如 "#,##0.00;(#,##0.00)": /** * Created by Shuai on 2016/7/11. */ public class Main { public static void main(String[] args) { // 正值 BigDecimal bigDecimal = BigDecimal.valueOf(-12211151515151.541666);

Java线程等待用法实例分析

本文实例讲述了Java线程等待用法.分享给大家供大家参考,具体如下: 线程等待 public class Hello { public static void main(String[] args) { A a = new A(); new Thread(new MyRun(a)).start(); new Thread(new MyRun1(a)).start(); } } class MyRun implements Runnable { private A a; public MyRun(