1、线程程序
一个线程在Java中使用 Thread的类 实例来描述
Thread 类是Java语言中一个重要的类,位于 Java.lang包中;
通过继承Thread 类来创建线程;通过 start() 这个方法调用线程,系统会自动调用run(),t 线程就开始执行;
我们可以通过 jconsole.exe 这个文件帮我们查看java执行期间的线程
2、创建线程
2.1 方法1 继承Thread类
- 继承 Thread类 ,重写 run()方法
- 创建 Thread实例,start()调用线程,自动调用run方法
class MyThread extends Thread{
@Override
public void run() {
while (true){
try {
Thread.sleep(1000); //Thread 的静态方法
}catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("开辟线程 1");
}
}
}
public static void main(String[] args) {
//多态向上转型 创建线程
Thread thread = new MyThread();
//开始调用线程 只能调用一次
thread.start();
while (true){
try {
Thread.sleep(1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main");
}
}
2.2 方法2 实现Runnable接口
- 实现 Runnable接口,重写run()
- 创建 Thread实例,调用Thread构造方法 将 Runnable对象作为target参数
- start()调用线程,自动调用run方法
class MyRunnable implements Runnable{
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程 2");
}
}
}
public class ThreadDome2 {
public static void main(String[] args) {
Runnable runnable = new MyRunnable();
//创建Thread,runnable作为参数
Thread thread = new Thread(runnable);
thread.start();
while (true){
try {
Thread.sleep(1000);
}catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("main");
}
}
}
以上两种写法没有区别,只是描述线程的入口方法不同
2.3 方法3 继承Thread,实现匿名内部类
跟在()后面,加大括号实现匿名内部类
public class ThreadDome3 {
public static void main(String[] args) {
Thread thread = new Thread() {
//重写,匿名内部类
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("使用匿名类创建 Thread 子类对象");
}
}
};
//启动 线程2
thread.start();
//
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("main");
}
}
}
2.4 方法4 实现Runnable接口,实现匿名内部类
跟在()后面,加大括号实现匿名内部类
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
//重写,匿名内部类
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("使用匿名类创建 Runnable 子类对象");
}
}
});
thread.start();
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main");
}
}
2.5 方法5 Lambda表达式,匿名内部类
lambda实现匿名内部类 作为参数,Thread()构造
public static void main(String[] args) {
Thread thread = new Thread(()->{
while (true){
System.out.println("lambda 创建Runnable对象,传参");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main");
}
}
3、总结
以上java中线程的创建 都和Thread类有关;
- Thread是java中用于实现多线程编程的类
- 在java中,每个线程都是一个Thread类的实例对象
- 通过创建Thread类的实例对象,就可以在程序中创建一个新的线程,从而实现多线程编程
在程序实现多线程过程:
3.1 创建Thread的实例对象
先创建Thread的实例对象,这种有两种方式
- 继承Thread类,重写run方法
- 实现Runnable接口,重写run方法
注意:想创建执行线程,主要是重写run方法
- run方法是表示线程的执行逻辑,在方法中写线程的代码执行逻辑,是线程生命周期的一部分
- run方法是线程执行的入口点,线程在运行时会自动调用该方法,从而执行线程的任务
- 重写 run() 方法是定义线程执行逻辑的关键
- 可以将run方法看做线程的main方法,main是程序的java主程序的入口点,是程序的起始点,是应用程序的主线程。main()负责启动应用程序,初始化状态,创建对象,执行应用程序的逻辑;
- run()方法是线程执行的入口点,在Thread类的实例对象调用 start()方法时,就会在程序中创建线程,自动调用run()方法(注意是自动调用,不要手动调用,那只是在main方法中调用了一次run方法)
优点:
- 实现简单;
- 可以重写Thread类中的其他方法,从而更好的控制线程;
- 可以直接用this关键字获取 线程对象
3.2 Runnable接口
Runnable是一个接口,它定义了一个没有参数和返回值的run()方法;实现了Runnable接口的类被看做一段“可执行代码:,可以被线程执行;
public interface Runnable {
public abstract void run();
}
实现Runnable接口的类可以看做run方法的单独定义,仅仅是提供了一个线程执行的逻辑方法,而不是一个完整的线程;完整的线程还是需要Thread来创建,Runnable实现的可以作为参数来实例化Thread类;
Thread类中有私有成员 Runnable类型的 target 用来接受 实现Runnable接口的实例对象
这种写的好处:
- 将线程的执行逻辑从线程类中分离出来,使代码更加清晰和易于维护;
- 继承了Thread类的不能继承其他类,Runnable接口实现避免了Java单继承的限制,因为一个类可以实现多个接口;
- 提高了代码的复用性,因为已实现Runnable接口的类可以被多个线程共享,也实现了资源的共享,多个线程可以共同享用一个Runnable对象中的数据;
缺点:
不能直接获取Thread对象,需要通过Thread.currentThread()方法返回当前执行代码的线程的引用。
3.3 创建线程
以上两种只是 创建了线程的对象,真正将线程创建到程序中的是 start() 方法
注意:
- 当调用start()方法时,线程才会被真正创建,start()方法会为线程分配资源,并使线程进入就绪状态,等待系统调度执行;
- 一个线程对象只能被 执行一次 start()方法,调用两次会抛出IllegalThreadStateException 异常
3.4 流程图
- 如果在main()方法中创建了其他线程,主线程和线程并发执行;
- 执行的顺序取决于操作系统和JVM对线程调度的具体情况;