在Java中,线程通常有五种状态:创建,就绪,运行,阻塞和死亡。
创建状态:在生成线程对象,并没有调用该对象的star方法,这时线程处于创建状态。
就绪状态:当调用了线程对象的start方法之后,该线程就进入就绪状态。但是此时线程调度程序还没有把该线程设置
为当前线程,此时处于就绪状态。在线程运行之后,从等待或者睡眠中回来之后,也会处于就绪状态。
运行状态:线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行run函数中的代码。
阻塞状态:线程正在运行的时候,被暂停 ,通常是为了等待某个事件的发生之后再运行。sleep,suspend,wait等方法
都可以导致线程阻塞。
死亡状态:如果一个线程的run方法执行结束或者被调用stop方法后,该线程就会死亡。对于死亡的线程,无法再使用start方法
令其进入就绪。
实现线程的方法
Java中实现并启动线程有两种方法:
1.写一个类继承Thread类,重写run方法,用start方法启动线程。
2.写一个类实现Runnable接口,实现run方法。用new Thread(Runnable target).start()方法来启动。
start()方法
用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。通过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法,这里方法 run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。run()方法
run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。总结:调用start方法方可启动线程,而run方法只是thread的一个普通方法调用,还是在主线程里执行。这两个方法应该都比较熟悉,把需要并行处理的代码放在run()方法中,start()方法启动线程将自动调用 run()方法,这是由jvm的内存机制规定的。并且run()方法必须是public访问权限,返回值类型为void。
Thread的子类要重写这个方法,通过Thread调用run()方法,执行线程的线程体。
调用start()后,线程会被放到等待队列,等待CPU调度,并不一定要马上开始执行,只是将这个线程置于可动行状态。然后通过JVM,线程Thread会调用run()方法,执行本线程的线程体。先调用start后调用run,这么麻烦,为了不直接调用run?就是为了实现多线程的优点,没这个start不行。
多线程就是分时利用CPU,宏观上让所有线程一起执行 ,也叫并发。
public class Test1 {
public static void main(String[] args) {
ThreadTest1 t1 = new ThreadTest1();
ThreadTest2 t2 = new ThreadTest2();
Thread thread1 = new Thread(t1);
Thread thread2 = new Thread(t2);
thread1.start();
thread2.start();
}
}
class ThreadTest1 implements Runnable {
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("ThreadTest1正在运行==========" + i);
}
}
}
class ThreadTest2 implements Runnable {
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("ThreadTest2正在运行==========" + i);
}
}
}
从执行结果来看,ThreadTest1和ThreadTest2是交叉执行,即并发执行的。
ThreadTest1正在运行==========0
ThreadTest2正在运行==========0
ThreadTest1正在运行==========1
ThreadTest2正在运行==========1
ThreadTest2正在运行==========2
ThreadTest2正在运行==========3
ThreadTest2正在运行==========4
ThreadTest2正在运行==========5
ThreadTest2正在运行==========6
ThreadTest2正在运行==========7
ThreadTest2正在运行==========8
ThreadTest2正在运行==========9
ThreadTest2正在运行==========10
ThreadTest2正在运行==========11
ThreadTest2正在运行==========12
ThreadTest1正在运行==========2
ThreadTest1正在运行==========3
ThreadTest1正在运行==========4
ThreadTest1正在运行==========5
ThreadTest2正在运行==========13
ThreadTest2正在运行==========14
ThreadTest2正在运行==========15
ThreadTest2正在运行==========16
ThreadTest2正在运行==========17
ThreadTest2正在运行==========18
ThreadTest1正在运行==========6
ThreadTest2正在运行==========19
ThreadTest1正在运行==========7
ThreadTest1正在运行==========8
ThreadTest1正在运行==========9
ThreadTest1正在运行==========10
ThreadTest1正在运行==========11
ThreadTest1正在运行==========12
ThreadTest1正在运行==========13
ThreadTest1正在运行==========14
ThreadTest1正在运行==========15
ThreadTest1正在运行==========16
ThreadTest1正在运行==========17
ThreadTest1正在运行==========18
ThreadTest1正在运行==========19
public class Test1 {
public static void main(String[] args) {
ThreadTest1 t1 = new ThreadTest1();
ThreadTest2 t2 = new ThreadTest2();
Thread thread1 = new Thread(t1);
Thread thread2 = new Thread(t2);
thread1.run();
thread2.run();
}
}
class ThreadTest1 implements Runnable {
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("ThreadTest1正在运行==========" + i);
}
}
}
class ThreadTest2 implements Runnable {
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("ThreadTest2正在运行==========" + i);
}
}
}
从运行结果来看,ThreadTest1和ThreadTest2是顺序执行的。
ThreadTest1正在运行==========0
ThreadTest1正在运行==========1
ThreadTest1正在运行==========2
ThreadTest1正在运行==========3
ThreadTest1正在运行==========4
ThreadTest1正在运行==========5
ThreadTest1正在运行==========6
ThreadTest1正在运行==========7
ThreadTest1正在运行==========8
ThreadTest1正在运行==========9
ThreadTest1正在运行==========10
ThreadTest1正在运行==========11
ThreadTest1正在运行==========12
ThreadTest1正在运行==========13
ThreadTest1正在运行==========14
ThreadTest1正在运行==========15
ThreadTest1正在运行==========16
ThreadTest1正在运行==========17
ThreadTest1正在运行==========18
ThreadTest1正在运行==========19
ThreadTest2正在运行==========0
ThreadTest2正在运行==========1
ThreadTest2正在运行==========2
ThreadTest2正在运行==========3
ThreadTest2正在运行==========4
ThreadTest2正在运行==========5
ThreadTest2正在运行==========6
ThreadTest2正在运行==========7
ThreadTest2正在运行==========8
ThreadTest2正在运行==========9
ThreadTest2正在运行==========10
ThreadTest2正在运行==========11
ThreadTest2正在运行==========12
ThreadTest2正在运行==========13
ThreadTest2正在运行==========14
ThreadTest2正在运行==========15
ThreadTest2正在运行==========16
ThreadTest2正在运行==========17
ThreadTest2正在运行==========18
ThreadTest2正在运行==========19
实现Runnable接口所具有的优势:
1.避免Java单继承的问题。
2.适合多线程处理同一个资源。
3.代码可以被多线程共享,数据独立,很容易实现资源共享。
4.线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类