目录
一、start:
start()方法是Thread类定义的,也是Thread类的默认执行入口,Thread是实现Runnable接口的。通过start直接调用run()方法,启动线程,从而达到了多线程的目的(真正实现了多线程运行),这样无需等待run方法体执行完毕,直接执行下面的代码。通常系统通过调用线程的start方法启动一个线程,使线程处于就绪队列(可执行态),此时并没有运行。这就意味着该线程可以被JVM来调度执行。在调度时,JVM会通过线程的run()方法来完成试机操作,当run方法结束之后,线程终止。
下面是一个多线程并发的例子:(t1t2两个线程并发执行)
package Thread;
class myRunnable1 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class myRunnable2 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(-i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class demo22 {
public static void main(String[] args) {
Thread t1 = new Thread(new myRunnable1());
Thread t2 = new Thread(new myRunnable2());
t1.start();
t2.start();
}
}
注:由于在线程的生命周期中,线程的状态由NEW ----> RUNABLE只会发生一次,因此,一个线程只能调用start()方法一次,多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。
二、 run:
run()方法是Runnable接口中定义的, 所有实现Runnable的接口的类都需要重写run方法,run方法是一个普通方法,能够被调用,是线程默认要执行的方法,是绑定操作系统的,也是线程执行的入口。它只是一个普通的函数调用,如果直接调用run方法,程序中依然只有主线程这一个线程,其程序执行的路径还是只有一条,还是要顺序执行,要等待run方法体执行完毕后才可继续执行下面的代码。但是这样并没有达到写线程的目的。
下面一个例子:(t1和t2按照顺序执行)
package Thread;
class myRunnable1 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class myRunnable2 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(-i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class demo22 {
public static void main(String[] args) {
Thread t1 = new Thread(new myRunnable1());
Thread t2 = new Thread(new myRunnable2());
t1.run();
t2.run();
}
}
三、 总结
通过两个例子我们可以知道调用start方法可启动线程,可以并发,而run方法只是thread的一个普通方法调用,还是在主线程里执行。这里的意思就是说,star()方法可以异步地调用run()方法,是异步执行,直接调用run()方法是同步执行,因此也就不能达到多线程的目的。这两个方法应该都比较熟悉,把需要并行处理的代码放在run()方法中,start()方法启动线程将自动调用 run()方法,这是由jvm的内存机制规定的。并且run()方法必须是public访问权限,返回值类型为void。
对线程的补充:
Java 的线程是通过java.lang.Thread类来实现的。我们可以通过创建Thread的实例来创建新的线程。每个线程都是通过某个特定Thread对象所对应的方法run()来完成其操作的,方法run()称为线程体。通过调用Thread类的start()方法来启动一个线程。
线程通常都有五种状态,创建、就绪、运行、阻塞和死亡。
- 第一是创建状态。在生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态。
- 第二是就绪状态。当调用了线程对象的start方法之后,该线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之后,从等待或者睡眠中回来之后,也会处于就绪状态。
- 第三是运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行run函数当中的代码。
- 第四是阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。sleep(),suspend(),wait()等方法都可以导致线程阻塞。
- 第五是死亡状态。如果一个线程的run()方法执行结束或者调用stop()方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪。
实现并启动线程有两种方法
- 写一个类继承自Thread类,重写run()方法。用start()方法启动线程
- 写一个类实现Runnable接口,实现run()方法。用new Thread(Runnable target).start()方法来启动
多线程原理:指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务。我们这里举个例子,比如玩游戏机时,只有一个游戏机(这里用游戏机代指cpu),可是有很多人要玩,于是,我们需要排队(start是排队),等CPU选中你就是轮到你,你就run(),当CPU的运行的时间片执行完,这个线程就继续排队,等待下一次的run()。
调用start()后,线程会被放到等待队列,等待CPU调度,并不一定要马上开始执行,只是将这个线程置于可动行状态。然后通过JVM,线程Thread会调用run()方法,执行本线程的线程体。先调用start后调用run,这么麻烦,为了不直接调用run?就是为了实现多线程的优点,没这个start不行。
1.start()方法来启动线程,真正实现了多线程运行。这时无需等待run方法体代码执行完毕,可以直接继续执行下面的代码;通过调用Thread类的start()方法来启动一个线程, 这时此线程是处于就绪状态,并没有运行。 然后通过此Thread类调用方法run()来完成其运行操作的,这里方法run()称为线程体,它包含了要执行的这个线程的内容, Run方法运行结束, 此线程终止。然后CPU再调度其它线程。
2.run()方法当作普通方法的方式调用。程序还是要顺序执行,要等待run方法体执行完毕后,才可继续执行下面的代码; 程序中只有主线程——这一个线程, 其程序执行路径还是只有一条, 这样就没有达到写线程的目的。
记住:多线程就是分时利用CPU,宏观上让所有线程一起执行 ,也叫并发。
参考文章:https://blog.youkuaiyun.com/weixin_61061381/article/details/126053230