程序:存放在电脑硬盘上的命令集合。 是静态的
进程:是程序运行之后,在内存中产生的数据。
线程:组成进程的最小单位。
比如:进程是执行100行的代码效果,线程是1行的代码的效果
每一个进程都是由N个线程组成的,至少由1线程组成
如何自定义线程?
第一种方式:继承Thread类
1.创建自定义线程类 继承 Thread类
2.在自定义线程类中 覆写run方法
3.创建自定义线程类对象
4.启动线程 调用start方法
注意事项:
①run方法 与 start方法 的区别
run : 顺序执行线程(没有并发效果) 直接执行不由CPU调度 达不到并发的效果 即执行完run方法才会往下执行
start: 启动线程 把方法加载线程调度池中,由CPU分配时间片来执行线程 (有并发效果)
②start方法不能重复调用 ==》否则抛出异常
③主线程:主方法由JVM的主线程调用
④在主线程与在主方法中创建的线程,在运行之后是完全独立的,没有关系
⑤ 运行java程序之后,至少有几个线程?
两个:主线程 + 垃圾回收线程(守护线程)
启动两个线程,CPU会在两个线程之间高速切换,看到的效果就是同时运行,其实2个线程是在以非常快的速度交替运行
第二种方式:实现Runnable接口
1.创建自定义类 并实现 Runnable接口
2.覆写run方法
3.创建自定义类对象
4.创建Thread类对象 ==》 调用Thread的构造方法:Thread(Runnable r),把上面创建的自定义类对象作为构造方法的参数
该对象包含了创建Runnable实现类对象
该实现类对象已经覆写了run方法
该Thread对象,本身就有start方法
5.启动线程 ==》调用Thread对象的start ,(CPU执行该Thread对象的run方法,从Runnable接口的实现类对象来的)
那么两种方式,哪一种更好?
第二种方式更好 ==》 原因:java是单继承语言,使用继承,就不能继承其他类了 ==> 在以后项目需要增加功能的时候,使用第二种方式,它的扩展性更强
方式1:
public class Demo {
public static void main(String[] args) {
//3.创建线程对象
A a= new A();
B b = new B();
//4.启动线程
a.start();
b.start();
}
}
//1.自定义线程类 继承Thread类
class A extends Thread{
//2.覆写run方法
public void run() {
for(int i=0;i<100;i++){
System.out.println("AAA ...");
}
}
}
//1.自定义线程类 继承Thread类
class B extends Thread{
//2.覆写run方法
public void run() {
for(int i=0;i<100;i++){
System.out.println("BBB ...");
}
}
}
运行结果图: (我们会发现 A和B 在交替出现)
方式2:
public class Demo {
public static void main(String[] args) {
//3.创建自定义类对象
MyThread1 m1 = new MyThread1();
MyThread2 m2 = new MyThread2();
/*
* 自定义类对象m1和m2 : 负责覆写run方法
* Thread对象t1和t2 : 负责启动线程
*/
//4.创建Thread类对象
Thread t1 = new Thread(m1);
Thread t2 = new Thread(m2);
//5.启动线程
t1.start();
t2.start();
}
}
//1.创建自定义类 实现 Runnable接口
class MyThread1 implements Runnable{
//2.覆写run方法
public void run() {
for(int i=0;i<100;i++){
System.out.println("... 111 ...");
}
}
}
//1.创建自定义类 实现 Runnable接口
class MyThread2 implements Runnable{
//2.覆写run方法
public void run() {
for(int i=0;i<100;i++){
System.out.println("... 222 ...");
}
}
}
运行结果图:(和方式1相同,结果都是交替打印的)