Java多线程


Java是一个多线程编程语言,这意味着我们可以使用Java开发多线程程序。

多线程程序包含可以同时运行的两个或多个部分,并且每个部分可以同时处理不同的任务,从而可以最佳地利用可用资源,尤其是在计算机具有多个CPU的情况下。

根据定义,多任务是指多个进程共享诸如CPU之类的通用处理资源。多线程将多任务的概念扩展到了应用程序中,你可以在其中将单个应用程序内的特定操作细分为各个线程。每个线程可以并行运行。操作系统不仅在不同的应用程序之间分配处理时间,还在应用程序内的每个线程之间分配处理时间。

多线程使你可以编写一种方式,使多个活动可以在同一程序中同时进行。

线程的生命周期


线程在其生命周期中会经历各个阶段。例如,线程是先生,启动,运行然后死亡的。

以下是生命周期的各个阶段:

  • 新建:新线程在新状态下开始其生命周期。它将保持这种状态,直到程序启动线程为止。也称为天生的线程.

  • 可执行:启动新出生的线程后,该线程将变为可运行状态。处于此状态的线程被视为正在执行其任务。

  • 等待:有时,线程在等待另一个线程执行任务时会转换为等待状态。仅当另一个线程发出信号通知等待的线程继续执行时,一个线程才转换回可运行状态。

  • 定时等待:可运行线程可以在指定的时间间隔内进入定时等待状态。当该时间间隔到期或等待事件发生时,处于此状态的线程将转换回可运行状态。

  • 终止(死):当可运行线程完成其任务或以其他方式终止时,它将进入终止状态。

线程优先级


每个Java线程都有一个优先级,可以帮助操作系统确定线程调度的顺序。

Java线程优先级在MIN_PRIORITY(常数1)和MAX_PRIORITY(常数10)之间。默认情况下,每个线程的优先级为NORM_PRIORITY(常数5)。

具有较高优先级的线程对程序更重要,应在较低优先级的线程之前为它们分配处理器时间。但是,线程优先级不能保证线程执行的顺序,并且很大程度上取决于平台。

通过实现可运行接口创建线程


如果你的类打算作为线程执行,则可以通过实现一个Runnable接口。你需要遵循下面3个步骤:

步骤1

第一步,你需要实现由Runnable接口。这个方法为线程提供了一个入口,你将把你的完整业务逻辑放在这个方法中。

以下是run()方法的一个简单语法:

public void run( )

步骤2

第二步,你将实例化一个Thread对象使用以下构造函数:

Thread(Runnable threadObj, String threadName);

线程对象是实现Runnable接口和线程名是赋予新线程的名称。

步骤3

创建Thread对象后,你可以通过调用来启动它start()方法,该方法执行对run()方法的调用。以下是start()方法的简单语法:

void start();

这是一个创建新线程并开始运行它的示例:

class RunnableDemo implements Runnable {
    private Thread t;
    private String threadName;
   
    RunnableDemo( String name) {
        threadName = name;
        System.out.println("Creating " +  threadName );
    }
   
    public void run() {
        System.out.println("Running " +  threadName );
        try {
            for(int i = 4; i > 0; i--) {
                System.out.println("Thread: " + threadName + ", " + i);
                //让线程休眠一会儿。
                Thread.sleep(50);
            }
        } catch (InterruptedException e) {
            System.out.println("Thread " +  threadName + " interrupted.");
        }
        System.out.println("Thread " +  threadName + " exiting.");
    }
   
    public void start () {
        System.out.println("Starting " +  threadName );
        if (t == null) {
            t = new Thread (this, threadName);
            t.start ();
        }
    }
}

public class TestThread {

    public static void main(String args[]) {
        RunnableDemo R1 = new RunnableDemo( "Thread-1");
        R1.start();
      
        RunnableDemo R2 = new RunnableDemo( "Thread-2");
        R2.start();
    }
}

这将产生以下结果:

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

通过扩展线程类创建线程


创建线程的第二种方法是创建一个扩展了新类的类。Thread该类使用以下两个简单步骤。这种方法在处理使用Thread类中的可用方法创建的多个线程时提供了更大的灵活性。

步骤1

你将需要覆盖run( )Thread类中提供的方法。该方法为线程提供了一个入口点,你将把完整的业务逻辑放入该方法中。以下是run()方法的简单语法:

public void run( )

步骤2

创建线程对象后,你可以通过调用来启动它start()方法,该方法执行对run()方法的调用。以下是start()方法的简单语法:

void start( );

这是前面为扩展Thread而重写的程序:

class ThreadDemo extends Thread {
    private Thread t;
    private String threadName;
   
    ThreadDemo( String name) {
        threadName = name;
        System.out.println("Creating " +  threadName );
    }
   
    public void run() {
        System.out.println("Running " +  threadName );
        try {
            for(int i = 4; i > 0; i--) {
                System.out.println("Thread: " + threadName + ", " + i);
                //让线程休眠一会儿。
                Thread.sleep(50);
            }
        } catch (InterruptedException e) {
            System.out.println("Thread " +  threadName + " interrupted.");
        }
        System.out.println("Thread " +  threadName + " exiting.");
    }
   
    public void start () {
        System.out.println("Starting " +  threadName );
        if (t == null) {
            t = new Thread (this, threadName);
            t.start ();
        }
    }
}

public class TestThread {

    public static void main(String args[]) {
        ThreadDemo T1 = new ThreadDemo( "Thread-1");
        T1.start();
      
        ThreadDemo T2 = new ThreadDemo( "Thread-2");
        T2.start();
    }
}

这将产生以下结果:

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

线程方法


以下是Thread类中可用的重要方法的列表。

序号方法与说明
1

public void start()

在单独的执行路径中启动线程,然后在此Thread对象上调用run()方法。

2

public void run()

如果使用单独的Runnable目标实例化了此Thread对象,则在该Runnable对象上调用run()方法。

3

public final void setName(String name)

更改线程对象的名称。还有一个用于检索名称的getName()方法。

4

public final void setPriority(int priority)

设置此Thread对象的优先级。可能的值在1到10之间。

5

public final void setDaemon(boolean on)

参数true表示此Thread为守护线程。

6

public final void join(long millisec)

当前线程在第二个线程上调用此方法,导致当前线程阻塞,直到第二个线程终止或经过指定的毫秒数。

7

public void interrupt()

中断此线程,如果由于某种原因而被阻止,则导致该线程继续执行。

8

public final boolean isAlive()

如果线程处于活动状态,则返回true,这是在线程启动之后但运行完成之前的任何时间。

先前的方法在特定的Thread对象上调用。 Thread类中的以下方法是静态的。调用静态方法之一对当前正在运行的线程执行操作。

序号方法与说明
1

public static void yield()

使当前正在运行的线程屈服于等待调度的具有相同优先级的任何其他线程。

2

public static void sleep(long millisec)

使当前正在运行的线程阻塞至少指定的毫秒数。

3

public static boolean holdsLock(Object x)

如果当前线程持有给定Object的锁,则返回true。

4

public static Thread currentThread()

返回对当前正在运行的线程的引用,该线程是调用此方法的线程。

5

public static void dumpStack()

打印当前正在运行的线程的堆栈跟踪,这在调试多线程应用程序时非常有用。

下面的ThreadClassDemo程序演示了Thread类的某些方法。考虑一堂课显示讯息实施Runnable

//文件名:DisplayMessage.java
//创建一个线程来实现Runnable

public class DisplayMessage implements Runnable {
    private String message;
   
    public DisplayMessage(String message) {
        this.message = message;
    }
   
    public void run() {
        while(true) {
            System.out.println(message);
        }
    }
}

以下是扩展Thread类的另一个类:

//文件名:GuessANumber.java
//创建一个线程来扩展线程

public class GuessANumber extends Thread {
    private int number;
    public GuessANumber(int number) {
        this.number = number;
    }
   
    public void run() {
        int counter = 0;
        int guess = 0;
        do {
            guess = (int) (Math.random() * 100 + 1);
            System.out.println(this.getName() + " guesses " + guess);
            counter++;
        } while(guess != number);
        System.out.println("** Correct!" + this.getName() + "in" + counter + "guesses.**");
    }
}

以下是使用上述类的主程序:

//文件名:ThreadClassDemo.java
public class ThreadClassDemo {

    public static void main(String [] args) {
        Runnable hello = new DisplayMessage("Hello");
        Thread thread1 = new Thread(hello);
        thread1.setDaemon(true);
        thread1.setName("hello");
        System.out.println("Starting hello thread...");
        thread1.start();
      
        Runnable bye = new DisplayMessage("Goodbye");
        Thread thread2 = new Thread(bye);
        thread2.setPriority(Thread.MIN_PRIORITY);
        thread2.setDaemon(true);
        System.out.println("Starting goodbye thread...");
        thread2.start();

        System.out.println("Starting thread3...");
        Thread thread3 = new GuessANumber(27);
        thread3.start();
        try {
            thread3.join();
        } catch (InterruptedException e) {
            System.out.println("Thread interrupted.");
        }
        System.out.println("Starting thread4...");
        Thread thread4 = new GuessANumber(75);
      
        thread4.start();
        System.out.println("main() is ending...");
    }
}

这将产生以下结果。你可以一次又一次地尝试此示例,每次都会得到不同的结果。

Starting hello thread...
Starting goodbye thread...
Hello
Hello
Hello
Hello
Hello
Hello
Goodbye
Goodbye
Goodbye
Goodbye
Goodbye
.......

Java多线程主要概念


在用Java进行多线程编程时,你将需要非常方便地使用以下概念:

  • 什么是线程同步?

  • 处理线程间通讯

  • 处理线程死锁

  • 主线程操作