多线程: 一个线程就是一条执行路径,如果能把执行路径用一条线画出来就是一条路径,就是单线程,一条路径画不出来叫多线程
一个Thread对象对应程序中的一个线程,JVM允许程序有多个线程
package test01;
/**
* 多线程的创建(不同于main)
* 方式一:继承Thread类
* 1.创建继承Thread类的子类(这个子类就是线程了)
* 2.重写Thread类中的run方法-->将创建的这个线程要做的事写在run方法中
* 3.创建这个子类的对象-->在主线程(main)中做
* 4.通过此对象调用Thread类中的start方法
* 例子:遍历100以内的所有偶数
*/
public class ThreadTest {
public static void main(String[] args) {
MyThread t=new MyThread();
t.start();
System.out.println("hello");
}
}
class MyThread extends Thread{
@Override
public void run() {
for(int i=0;i<100;i++){
if(i%2==0){
System.out.println(i);
}
}
}
}
执行过程:
先进main方法,main即主线程,然后造一个对象( MyThread t1=new MyThread();是在主线程中做的)。调用start也是主线程做的,调完之后,start方法会去调run方法,执行我们创建的线程(独立执行run方法)
start() 方法的两个作用:
1)导致此线程开始执行(调用之前都没有执行我们做的这个线程);
2)Java虚拟机调用此线程的run方法。 (我们创建的这个线程是在主线程中造的)
输出hello是在主线程中做的。此时既有主线程也有分线程在执行,即有多个线程在执行,hello在console中的输出结果的哪个位置输出是不确定的,和具体CPU有关,每次执行的结果不一样
注意:
如果不start,直接t.run()是不可以的,此时没有语法错误,不会报错,运行也不会抛异常。只是hello一定在100以内所有偶数输出完之后才输出,因为此时没有开启一个新的线程,只是造对象调方法,run方法中的东西仍然是在主线程中做的
验证: 可以利用System.out.println(Thread.currentThread().getName());获得当前语句所在线程的名字,此时在main中,在子类中调用的输出结果都是main
如果在main中用t.start(),System.out.println(Thread.currentThread().getName())在子类中的结果为Thread-0(是系统给我们造的线程起的默认名字),在main方法中为main
如果我们想再启动一个线程,遍历一百以内的偶数,能不能在main方法中原来的t.start()下面再写一个t.start()?不能,会抛异常IllegalThreadStateException
首次调用start不会抛异常,再次调用就抛出异常,就是说一个线程只能调一次start。
可以这样:重新创建一个线程的对象,去调用start方法
MyThread t2=new MyThread();
t2.start();//这样是可以的
创建Thread类的匿名子类的方式:
package test01;
/**
*练习:
*可以采用简便的方式,如果只用一次后面不用了,可以考虑使用创建Thread类的匿名子类的方式
*/
public class ThreadDemo {
public static void main(String[] args) {
//创建匿名子类并启动线程,调用重写的run方法
new Thread(){//new的子类没有名字
public void run(){
for(int i=0;i<100;i++){
System.out.println(i);
}
}
}.start();
}
}