线程创建详解
线程创建包含线程生命周期中的 新建、就绪、运行 三种状态,相关的api为java.lang.Thread 类
① 新建状态:就是刚使用new方法,new出来的线程
如常见的两种方式
方式一:继承Thread类,并初始化Thread子类
继承Thread的子类 ticketWindow1 = new 继承Thread的子类("一号柜台");
方式二:实现Runnaable接口
final Runnable接口的类 ticketWindowRunnable = new Runnable接口的类();
Thread thread1 = new Thread(ticketWindowRunnable,"一号窗口");
两种方式创建时候会调用Thread类的构造方法完成init() 初始化操作(Thread类有多个构造方法,所以初始化类有多种形式)
②就绪:就是调用的线程的start()方法后,这时候线程处于等待CPU分配资源阶段,谁先抢的CPU资源,谁开始执行;
Thread.start();
源码如下:
此时会调用 private native void start0()方法,Native Method就是一个java调用非java代码的接口。
start0() 源码如下
可以看到start0() 的底层会调用run方法启动线程。完成 ③线程运行
启动模型:
关于run方法和Start方法
java里面创建线程之后必须要调用start方法才能真正的创建一个线程,该方法会调用虚拟机启动一个本地线程,本地线程的创建会调用当前系统创建线程的方法进行创建,并且线程被执行的时候会回调 run方法进行业务逻辑的处理
- 调用start()时,会创建一个新的子进程并启动
- 调用run()时,支持thread的普通方法调用,依旧在主线程中调用(比如在main方法中启动,当前线程为main线程)。
两种方式创建线程
方式一:继承thread类
- 写一个类继承Thread 并且重写run方法
public class TicketWindow extends Thread {
private final String name;
private static final int MAX = 50;
private static int index = 1;
public TicketWindow(String name) {
this.name = name;
}
@Override
public void run() {
while (index <= MAX) {
System.out.println("柜台:" + name + "当前的号码是:" + (index++));
}
}
}
- 初始化并调用start方法
```java
public class Bank {
public static void main(String[] args) {
TicketWindow ticketWindow1 = new TicketWindow("一号柜台");
ticketWindow1.start();
TicketWindow ticketWindow2 = new TicketWindow("二号柜台");
ticketWindow2.start();
TicketWindow ticketWindow3 = new TicketWindow("三号柜台");
ticketWindow3.start();
}
}
注意:
Java虚拟机会在初始化子类的时候默认初始化子类的父类。
如果父类的构造方法是带参数的,而且没有无参数的构造方法,那么在子类的构造方法中必须显式地调用父类的构造方法。
如果父类的构造方法是无参数的,那么在子类中写不写都可以,不写的话会隐式地调用。
所以初始化子类时候会默认调动父类无参构造方法完成初始化操作。
方式二:实现Runnable 接口
- 写一个类继承Runable 接口,重写Runable接口
public class TicketWindowRunnable implements Runnable{
private int index =0;
private final static int MAX=50;
@Override
public void run() {
while (index<=MAX){
System.out.println("当前窗口是"+Thread.currentThread().getName()+"叫到的号码为"+index++);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Runable底层只有一个抽象方法 run
2.通过构造函数,Thread(Runnable target, String name) 初始化Thread对象
final TicketWindowRunnable ticketWindowRunnable = new TicketWindowRunnable();
Thread thread1 = new Thread(ticketWindowRunnable,"一号窗口");
3. 调用 Thread.start方法启动线程
完整代码:
public class BanKversion2_2 {
public static void main(String args[]){
final TicketWindowRunnable ticketWindowRunnable = new TicketWindowRunnable();
Thread thread1 = new Thread(ticketWindowRunnable,"一号窗口");
Thread thread2 = new Thread(ticketWindowRunnable,"二号窗口");
Thread thread3 = new Thread(ticketWindowRunnable,"三号窗口");
thread1.start();
thread2.start();
thread3.start();
}
}
thread类与runable接口区别
runnable优点:
- runnable实现了资源共享,适合相同程序的多个线程去处理同一资源的情况。
- 可以避免由于Java的单继承特性带来的局限。
- 增强了程序的健壮性,代码能够被多个线程共享,代码与数据是独立的。
如果不需要改变线程中除了run方法之外的其他代码,建议使用runnable接口
线程初始化方式
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}
参数含义:线程组,策略接口,线程名,栈大小
- 线程名 --> 规则:Thread-0++
- ThreadGroup --> 未传入ThreadGroup 使用父线程
- Runnable --> 未传入Runable 则不执行
- stackSize --> 高度依赖平台,有些平台不会有影响
几种初始化方法案例
public class CreateThread {
public static void main(String args[]){
Thread t1 = new Thread();
Thread t2 = new Thread(){
@Override
public void run(){
System.out.println("--重写run方法--");
}
};
Thread t3 = new Thread("MyThread");
Thread t4 = new Thread(()->{
System.out.println(" Runnable ...");
});
Thread t5 = new Thread(()->{
System.out.println("Runable ...");
},"RunnableThread");
Thread t6 = new Thread(null, new Runnable() {
int count=0;
@Override
public void run() {
try {
add(1);
}catch (Error e){
System.out.println(count);
}
}
private void add (int i){
count++;
add(i+1);
}
},"Test",1<<24);
}
}