现在的位置: 首页 > 综合 > 正文

Java Thread

2013年11月21日 ⁄ 综合 ⁄ 共 6046字 ⁄ 字号 评论关闭

A thread is a single sequential flow of control within a program.(线程是一个进程中一段独立的控制流)。一个进程可以拥有若干个线程。Java通过java.lang.Thread类来支持多线程。在Thread类中封装了独立的有关线程执行的数据和方法,并将多线程与面向对象的结构合为一体。

Java提供了两种方法创建线程,一种是继承Thread类并重写run方法,另一种则是实现接口Runnable

继承Thread

import java.lang.Thread;

import java.lang.Math;

import java.lang.InterruptedException;

public class SimpleThread extends Thread {

    //构造函数,设置线程的名字。否则自动生成的名字格式为 "Thread-"+n, n是整数。

    public SimpleThread(String str) {

        super(str);

    }

    public void run() {

        for (int i = 0; i < 10; i++) {

            System.out.println(i + " " + getName());

            try {

                //sleep

                sleep((long)(Math.random() * 1000));

            } catch (InterruptedException e) {}

        }

        System.out.println("DONE! " + getName());

    }

}

 

//Threadstart方法

public native synchronized void start()

使该线程开始执行; Java 虚拟机调用线程 run 方法。

结果是两个线程同时运行: 当前线程 (方法 start 返回的线程) 和另一个线程 (执行方法 run 的线程)

 

//Threadrun方法

public void run()

如果该线程是用不同的Runnable运行对象构造的, 则该Runnable对象的run方法被调用; 否则, 该方法不做任何事就返回。

Thread 的子类必须覆盖此方法。

抛出: IllegalThreadStateException如果该线程已经启动。

 

虽然run()函数实现了多个线程的并行处理,但不能直接调用run()函数,而是通过调用start()函数来调用run()函数。在调用start()的时候,start()函数会首先进行与多线程相关的初始化(这也是为什么不能直接调用run()函数的原因),然后再调用run()函数。

public class TwoThreadsDemo {

    public static void main (String[] args) {

        new SimpleThread("Jamaica").start();

        new SimpleThread("Fiji").start();

    }

}

实现接口Runnable

    如果有一个类,它已继承了某个类,又想实现多线程,那就可以通过实现Runnable接口来实现。

    1) Runnable接口只有一个run()函数。

    2) 把一个实现了Runnable接口的对象作为参数产生一个Thread对象,再调用Thread对象的start()函数就可执行并行操作。如果在产生一个Thread对象时以一个Runnable接口的实现类的对象作为参数,那么在调用start()函数时,start()会调用Runnable接口的实现类中的run()函数。

import java.lang.Thread;

import java.lang.System;

import java.lang.Math;

import java.lang.InterruptedException;

import java.lang.Runnable;

class MyThread implements Runnable{

    String name;

    private Thread myThread = null;

    public MyThread(String name){

      this.name = name;

    }

    public void start() {

        if (myThread == null) {

            myThread = new Thread(this, "Clock");

            myThread.start();

        }

    }

    public void run(){

        Thread curThread = Thread.currentThread();

        if (curThread == myThread) {

            for (int i = 0; i < 10; i++) {

                System.out.println(i + " " + getName());

                try {

                    //sleep

                    //接口Runnable中没有方法sleep()

                    Thread.sleep(1000);

                } catch (InterruptedException e) {}

            }

            System.out.println("DONE! " + getName());

        }

    } 

}

总结:

两种提供线程run方法的途径:

1. 继承java.lang.Thread类并重写run方法

2. 实现java.lang.Runnable接口并实现run方法

如果类是从其它类继承下来的,则应该选用实现java.lang.Runnable接口的方法

 

若干常用的方法

currentThread()              这是一个类方法,返回当前正在执行的线程。

isAlive()                    判别一个线程是否仍然活着,包括这个线程正在执行或有机会被执行。返回一个布尔值。

suspend()                  悬挂起某个线程,并使得这个线程只可被resume()方法激活。

resume()                   suspend()配合使用。唤醒线程。

yeild()                       强迫线程交出执行权利供其它线程使用。

stop()                       使线程进入死亡(dead)状态。

 

线程的生命周期

●新线程态(New Thread)

    当用new方法创建一个线程对象后,它仅仅是一个空的线程对象,没有分配有任何系统资源。当线程处于该状态时,只能只能启动或终止它任何其他操作都会引发IllegalThreadStateException异常

 

●可运行态(Runnable)    start()方法产生运行线程所必须的资源,调度线程执行,并且调用线程的run()方法。在这时线程处于可运行态。该状态不称为运行态是因为这时的线程并不总是一直占用处理机。特别是对于只有一个处理机的PC而言,任何时刻只能有一个处于可运行态的线程占用处理 机。Java通过调度来实现多线程对处理机的共享。

 

●非运行态(Not Runnable)

当下面的任何一个情况发生时,线程进入不可运行状态

A thread becomes Not Runnable when one of these events occurs:

1) If a thread has been put to sleep, then the specified number of milliseconds must elapse.(sleep()方法被调用)

2) suspend()方法被调用;

3) The thread calls the wait method to wait for a specific condition to be satisifed. (线程使用wait()来等待条件变量)

4) The thread is blocking on I/O. (线程处于I/O等待)

 

在第三种情况发生时,线程处于等待状态(等待某个能使它返回可运行状态的事件发生)即使处理器空闲,线程也无法运行。当可使线程返回运行状态的条件满足时,线程处于可运行状态,一旦处理器可用,线程将会再次运行。(例如被方法suspend()挂起的进程就要等待方法resume()方可被唤醒)

For each entrance into the Not Runnable state, there is a specific and distinct escape route that returns the thread to the Runnable state. An escape route works only for its corresponding entrance. For example, if a thread has been put to sleep, then the specified number of milliseconds must elapse before the thread becomes Runnable again. The following list describes the escape route for every entrance into the Not Runnable state:

(对每一个进入非运行状态的入口,都有一个特殊且明确的回路返回到线程的可运行状态。该回路紧紧为对应的入口工作。例如一个线程sleep,必须经过一段时间后才能返回可运行状态。以下的列表描述每一个进入非运行状态入口对应的回路)

If a thread has been put to sleep, then the specified number of milliseconds must elapse.(如果线程sleep,必须等待设定的时间)

If a thread is waiting for a condition, then another object must notify the waiting thread of a change in condition by calling notify or notifyAll. More information is available in Synchronizing Threads. (如果线程等待条件,那么其它的对象必须通过改变条件来通知等待的线程)

If a thread is blocked on I/O, then the I/O must complete. (如果线程处于I/O等待,则I/O操作必须完成)

 

●死亡态(Dead)

run()方法返回,或别的线程调用stop()方法,线程进入死亡态 。通常Applet使用它的stop()方法来终止它产生的所有线程。

 

The isAlive Method

如果线程已经运行并且没有停止则isAlive方法返回true. 如果isAlive方法返回false,则表示该线程可能是一个新线程或者是进入死亡状态。如果isAlive方法返回true,线程既可以是可运行的也可以是不可运行的。因此不能通过isAlive区分新线程和死亡状态的线程,只能区分可运行线程和不可运行线程

 

线程的同步

生产者/消费者模型

如果一个线程为另一个提供服务,那么我们把提供服务的线程称为生产者(Producer),另外一个线程称为消费者(consumer)

假设生产者产生0-9的整数并存储在一个公共对象CubbyHole中,消费者从CubbyHole对象中获取生产者生成的整数并打印出来。假定生产者线程每生产一个数都会sleep一段随机时间。

    Class CubbyHole {

        private int contents;

        public int get() {

            return contents;

        }

        public void put(int contents) {

            this.coutents = contents;

        }

    }

 

    //Producer

    Class Producer extends Thread {

        private Cubbyhole hole;

        public Producer(Cubbyhole hole) {

            this.hole = hole;

        }

        public void run() {

            for (int i=0; i<10; i++) {

                hole.put(i);

                try {

                    sleep((long)(Math.random()*100));

                } catch (InterruptedException ex) {

                    System.out.println("Thread Interrupted");

                    System.out.println(ex.getStackTrace());

                }

            }

        }

    }

 

    //Consumer

    public class Consumer extends Thread {

        private Cubbyhole hole;

        public Consumer(Cubbyhole hole){

            this.hole = hole;

        }

        public void run() {

            for (int i=0; i<10; i++) {

                System.out.println(hole.get());

            }

        }

    }

在本例中生产者(Producer)和消费者(Consumer)共享公共的资源--CubbyHole对象。在上述程序中,同步问题将会发生在ProducerConsumer线程之间。如果Producer生成数据速度大于Consumer获取速度或者是Consumer获取速度大于Producer生产速度,Consumer获取的结果都是错误的。实际上,我们需要的是Consumer所取得的数据是Producer每一次生成的数据。

ProducerConsumer的活动在两个方法必须是同步的。

首先,该两个线程必须不能同时访问

抱歉!评论已关闭.