多线程
线程:
线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程。
多线程就是一个程序中有多个线程在同时执行。
java中的线程:
在cmd(或powershell)输入java classname后,启动JVM,并加载对应的class文件。虚拟机会从main方法开始执行程序代码,直至把main方法的代码执行结束这个执行路径(线程)在java中被称为主线程(main线程——该线程的名字即为main)。
Thread类:
java.lang.Thread,实现了Runnable接口
构造方法:
Thread() 分配新的Thread对象
Thread(String name) 分配新的Thread对象,将指定的name作为该线程名字
常用方法:
void start() 使该线程开始执行;Java虚拟机调用该线程的run()方法。
void run() 该线程要执行的操作。
static void sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
创建新执行线程的两种方法:
方法一:创建类继承Thread类,该子类应重写Thread类的run()方法(因为Thread的run()的方法体为空)。将类声明为Thread的子类,通过该子类创建对象,使用start()方法开启线程。(start()会调用run()方法)
//Demo.java
public class Demo01 {
public static void main(String[] args) {
//创建自定义线程对象
MyThread mt = new MyThread("新的线程!");
//开启新线程
mt.start();
//在主方法中执行for循环
for (int i = 0; i < 10; i++) {
System.out.println("main线程!"+i);
}
}
}
class MyThread extends Thread {
//定义指定线程名称的构造方法
public MyThread(String name) {
//调用父类的String参数的构造方法,指定线程的名称
super(name);
}
/**
* 重写run方法,完成该线程执行的逻辑
*/
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName()+":正在执行!"+i);
}
}
}
注:调用该对象的run方法可以执行,但是并不会开启线程,即只是想普通类一样调用方法run()。而线程对象调用start时开启线程,并让JVM调用run方法在开启的线程中执行。
//ThreadDemo.java
class MyThread extends Thread { //继承Thread
MyThread(String name){
super(name);
}
//复写其中的run方法
public void run(){
for (int i=1;i<=20 ;i++ ){
System.out.println(Thread.currentThread().getName()+",i="+i);
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
//创建两个线程任务
MyThread d = new MyThread();
MyThread d2 = new MyThread();
d.run();//没有开启新线程, 在主线程调用run方法
d2.start();//开启一个新线程,新线程调用run方法
}
}
注:如何获取线程名字?Thread类中有如下方法:
static Thread currentThread() 返回对当前正在执行的线程对象的引用。
String getName() 返回该线程的名称。
由于currentThread()是静态方法,所以直接使用Thread.currentThrea().getName()获取当前对象的名字。
方法二:创建类实现Runnable接口,实现run()方法。声明该类并创建对象,传入到Thread类(或其子类)的构造方法中,使用start()开启线程。
//Demo02.java
class Demo02 {
public static void main(String[] args) {
//创建线程执行目标类对象
Runnable runn = new MyRunnable();
//将Runnable接口的子类对象作为参数传递给Thread类的构造函数
Thread thread = new Thread(runn);
Thread thread2 = new Thread(runn);
//开启线程
thread.start();
thread2.start();
for (int i = 0; i < 10; i++) {
System.out.println("main线程:正在执行!"+i);
}
}
}
public class MyRunnable implements Runnable{
//定义线程要执行的run方法逻辑
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("我的线程:正在执行!"+i);
}
}
}
Thread类中有构造方法用于接收Runnable的实现类的对象:
Thread(Runnable target) 分配新的Thread对象,以便将target作为其运行对象
Thread(Runnable target, String name) 分配新的Thread对象,以便将target作为其运行对象,将制定的name作为其名称。
注:为什么需要定一个类去实现Runnable接口呢?继承Thread类和实现Runnable接口有啥区别呢?实现Runnable接口,避免了继承Thread类的单继承局限性。覆盖Runnable接口中的run方法,将线程任务代码定义到run方法中。创建Thread类的对象,只有创建Thread类的对象才可以创建线程。线程任务已被封装到Runnable接口的run方法中,而这个run方法所属于Runnable接口的子类对象,所以将这个子类对象作为参数传递给Thread的构造函数,这样,线程对象创建时就可以明确要运行的线程的任务。