一.线程的调度
Java提供一个线程调度器来监控程序中启动后进入可运行状态的所有线程。线程调度器按照线程的优先级决定调度哪些线程来执行,具有高优先级的线程会在较低优先级的线程之前得到执行。同时线程的调度是抢先式的,即如果当前线程在执行过程中,一个具有更高优先级的线程进入可执行状态,则该告优先级的线程会被立即调度执行。
多个线程运行时,若线程的优先级相同,由操作系统按时间片轮转方式和独占方式来分配线程的执行时间。
在Java中线程的优先级是用数字来表示的,分为三个级别:
低优先级:Thread.MIN_PRIORITY,数值为1 (2~4)
缺省优先级: Thread. NORM_PRIORITY,数值为5
高优先级:Thread.MAX_PRIORITY,数值为10 (6~9)
具有相同优先级的多个线程,若它们都为高优先级Thread.MAX_PRIORITY,则每个线程都是独占式的,也就是说这些线程将被顺序执行;若该优先级不为高优先级,则这些线程将同时执行,也就是说这些线程的执行是无序的。
线程被创建后,其缺省的优先级是缺省优先级Thread. NORM_PRIORITY。可以用方法 int getPriority()来获得线程的优先级,同时也可以用方法 void setPriority( int p ) 在线程被创建后改变线程的优先级。
二.线程的通信
管道流可以连接两个线程间的通信。下面的例子里有两个线程在运行,一个写线程往管道流中输出信息,一个读线程从管道流中读入信息。
- class myWriter extends Thread
- {
- private PipedOutputStream outStream; //将数据输出
- private String messages[] = { "Monday", "Tuesday ", "Wednsday",
- "Thursday","Friday", "Saturday", "Sunday" };
- public myWriter(PipedOutputStream o)
- {
- outStream = o;
- }
- public void run()
- {
- PrintStream p = new PrintStream( outStream );
- for( int i = 0; i < messages.length; i++)
- {
- p.println( messages[i] );
- p.flush();
- System.out.println("Write:" + messages[i] );
- }
- p.close(); p = null;
- }
- }
- class myReader extends Thread
- {
- private PipedInputStream inStream; //从中读数据
- public myReader(PipedInputStream i)
- {
- inStream = i;
- }
- public void run()
- {
- String line;
- DataInputStream d;
- boolean reading = true;
- d = new DataInputStream( inStream );
- while( reading && d != null)
- {
- try{
- line = d.readLine();
- if( line != null ) System.out.println( ”Read: " + line );
- else reading = false;
- }catch( IOException e){}
- }
- try{
- Thread.currentThread().sleep( 4000 );
- }catch( InterruptedException e ){}
- }
- }
- public class Pipethread
- {
- public static void main(String args[])
- {
- Pipethread thisPipe = new Pipethread();
- thisPipe.process();
- }
- public void process()
- {
- PipedInputStream inStream;
- PipedOutputStream outStream;
- PrintStream printOut;
- try{
- outStream = new PipedOutputStream();
- inStream = new PipedInputStream(outStream);
- new myWriter( outStream ).start();
- new myReader( inStream ).start();
- }catch( IOException e ){ }
- }
- }
三.多线程的互斥与同步
通常,一些同时运行的线程需要共享数据。在这种时候,每个线程就必须要考虑其他与他一起共享数据的线程的状态与行为,否则的话就不能保证共享数据的一致性,从而也就不能保证程序的正确性。
产生这种问题的原因是对共享资源访问的不完整。为了解决这种问题,需要寻找一种机制来保证对共享数据操作的完整性,这种完整性称为共享数据操作的同步,共享数据叫做条件变量。
在Java语言中,引入了“对象互斥锁”的概念(又称为监视器、管程)来实现不同线程对共享数据操作的同步。 “对象互斥锁”阻止多个线程同时访问同一个条件变量。
在Java语言中,有两种方法可以实现“对象互斥锁”:
用关键字volatile来声明一个共享数据(变量);
用关键字synchronized来声明一个操作共享数据的方法或一段代码。
为了解决所出现的问题,在Java语言中可以用wait () 和notify()/notifyAll()方法用来协调线程间的读取关系。 wait()方法的作用是让当前线程释放其所持有的“对象互斥锁”,进入wait队列(等待队列);而notify()/notifyAll()方法的作用是唤醒一个或所有正在等待队列中等待的线程,并将它(们)移入等待同一个“对象互斥锁”的队列。
需要指出的是: notify()/notifyAll()方法和wait ()方法都只能在被声明为synchronized的方法或代码段中调用。
小结:
1. 实现线程有两种方法:
实现Ruannable接口
继承Thread类
2. 当新线程被启动时,Java运行系统调用该线程的run()方法,它是Thread的核心。
3. 线程有四个状态:创建、可运行、不可运行、死亡。
4. 在applet中通常在其start()方法中创建线程,在stop()方法中终止线程。
5. 线程间的通信方式有两种:管道流和共享中间类。
6. 两个或多个线程竞争资源时,需要用同步的方法协调资源。
7. 多个线程执行时,要用到同步方法,即使用synchronized的关键字设定同步区。
8. wait和notify起协调作用。