主线程
执行主(main)方法的线程就是主线程。JVM执行main方法,main方法会进入到栈内存,JVM会找操作系统开辟一条main方法通向CPU的执行路径。CPU就可以通过这个路径来执行main方法。而这个路径有一个名字,叫主线程。
Java程序中只有一个线程,执行从main方法开始,从上到下依次执行就是单线程程序。
创建多线程程序的第一种方式:
创建Thread类的子类对象
Java使用java.lang.Thread类代表线程。所有的线程对象都必须是Thread类或者其子类的实例。每个线程的作用是完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码。Java使用程序执行体来代表这段程序流。
Java中通过继承Thread类来创建并且启动多线程的步骤如下:
- 创建一个Thread的子类
- 在Thread的子类中重写run方法,设置线程任务。该run()方法的方法体就代表了线程需要完成的任务,因此把run()称之为线程执行体。
- 创建Thread的子类对象
- 调用Thread类中的方法start方法,开启线程。执行run方法中的方法体
代码举例:
创建新的线程
package demo03; //继承Thread类,创建子类 public class MyThread extends Thread { // 重写run 方法 @Override public void run() { // 新的线程要做什么 for (int i = 0; i < 3; i++) { System.out.println("run"+ i); } } }
定义测试类
package demo03; public class MyThreadTest { public static void main(String[] args) { //创建子线程对象 MyThread myThread = new MyThread(); // 启动线程 myThread.start(); //主线程里的循环 for (int i = 0; i < 3; i++) { System.out.println("main" + i); } } }
执行结果
多线程的原理
随着Thread子类对象的start方法启动,另外一个新的线程也就启动了。这样整个应用就是多线程了。多线程执行,在栈内存中,其实每一个执行线程都有一片自己所属的栈内存空间。进行方法的压栈和弹栈。多个线程之间毫不影响。
Java.lang.Thread类的构造方法
Thread类常用方法
- 使用Thread类中的方法 public String getName() 返回该线程的名称
- 先获取当前正在执行的线程,使用线程中的方法 public static Thread currentThread() 返回当前正在执行的线程的引用。在使用getName返回线程名称
- public void start():开启线程。JJVM调用此线程的run方法
- public void run():此线程要执行的任务,写run里面的代码体
- public static void sleep(long millis):使当前正在执行的线程以指定的毫秒数暂停。
- public static Thread currentThread() 返回当前正在执行的线程的引用。
创建多线程程序的第二种方式
实现Runnable 接口
Java.lang.Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称之为run的无参数方法
步骤如下:
- 创建一个Runnable 接口的实现类
- 在实现类中重写Runnable接口的run方法,设置线程任务
- 创建一个Runnable接口的实现类对象
- 创建Thread类对象,构造方法中传递Runable接口的实现类对象
- 调用Thread类中的start方法,开启新的线程执行run方法
Thread 和Runnable的区别
如果一个类继承Thread,则不适合资源共享。但是如果实现了Runnable接口的话,很容易实现资源共享。
实现Runnable接口比继续Thread类的优势如下:
- 适合多个相同的程序代码的线程去共享同一个资源
- 解决了Java单继承 的局限性
- 实现了解耦操作,代码和线程之间是独立的
- 线程池只能放入实现Runnable 或者Callable类的线程,不能直接放入继承Thread的类
结论:
优先使用第二种方式创建多线程
匿名内部类实现线程的操作
匿名内部类可以简化代码
应用场景
匿名内部类必须继承一个父类或者实现一个父接口。实现类只需要使用唯一一次。这种情况下,我们就可以使用匿名内部类。
匿名内部类定义格式:
前提
匿名内部类必须继承一个父类或者实现一个父接口
格式解析:
- new:创建对象的动作
- 接口名称:就是匿名内部类需要实现哪个接口
- {..}这才是的内容
注意事项:
- 匿名内部类,在创建对象的时候。只能使用唯一一次。
- 如果希望多次创建,对象或者多次使用对象,则不能使用任何匿名的类或者对象
- 匿名内部类是省略了(实现类或者子类的名称)。匿名对象是省略的对象名称
代码举例:
package demo01; public class RunnableTest { public static void main(String[] args) { //匿名内部类简化代码操作 new Thread(new Runnable() { @Override //线程要做的事情 public void run() { for (int i = 0; i < 3; i++) { System.out.println("sun" + i); } } //开启线程 }).start(); for (int i = 0; i < 3; i++) { System.out.println("main" + i); } } }
执行结果