文章目录
-
- 方式一:继承 Thread 类
-
- 提问:这个run()方法究竟是从哪里来的呢?
- 为什么要有第二种启动线程的方式
- 方式二:实现 Runnable 接口
- 总结:
方式一:继承 Thread 类
继承 Thread 类创建一个新的线程语法:
public class ThreadTest extends Thread{ @Override public void run() { // TODO Auto-generated method stub super.run(); } }
别怕,我们一层层分析。
当我们的自定义类继承了 Thread 类后,必须要实现run()方法。要算是一个有意义的线程
为什么这么说?
简单理解:
把线程要做的事情放到run()方法里,当线程启动后,会直接执行run()方法里面的所有代码。
好,那么问题来了。
提问:这个run()方法究竟是从哪里来的呢?
问得很好,run() 方法上方有一个@Override 标记,代表它是一个抽象方法,我们都知道子类是必须要继承父类 Thread的抽象方法的,而 Thread 又实现了Runnable 接口,接口中的方法全都是抽象方法,且不能有方法体,所以说,知道怎么来的了吧!
要想让线程能够得到执行,我们需要启动线程,这时候线程才能拿到cpu时间片从而才能启动
启动线程语法:
public static void main(String[] args){ new ThreadTest().start(); }
例1:
public class ThreadTest extends Thread { //继承 Thread 类 private int count = 10; public void run() { //重写 run() 方法 while(true) { System.out.print(count + " "); //打印 count 变量 if(--count == 0) { //使 count 变量自减,当自减为 0 时,退出循环 return; } } } public static void main(String[] args) { new ThreadTest().start(); } } class A extends Thread{ @Override public void run() { // TODO Auto-generated method stub super.run(); } }
结果为:
10 9 8 7 6 5 4 3 2 1
重要结论:
如果不调用start() 方法,线程永远都不会启动,在主方法没有调用start()方法之前,Thread 对象只是一个实例,而不是一个真正的线程。
为什么要有第二种启动线程的方式
学习第二种方式之前,我们需要知道,为什么有1种实现了以后还要搞第二种不是浪费时间吗,不,开发者可比我们聪明多了,针对不同的情景,我们会使用不同的方式去实现。
具体原因:
如果程序员需要继承其他类(非Thread 类),因为Java不能支持多继承,此时还要使当前类实现多线程,那么就可以通过 Runnable 接口来实现。
所以我们知道了第二种方式诞生原因后,就一起来学习吧
方式二:实现 Runnable 接口
语法:
public class Thread extends Object implements Runnable
其实 Thread 类它实现了 Runnable 对象,其中的 run()方法正是对 Runnable 接口中的 run() 方法的具体实现。
实现 Runnable 接口创建线程的流程图
例1:
import java.awt.Container; import java.net.URL; import javax.swing.*; public class SwingAndThread extends JFrame { private JLabel jl = new JLabel(); //声明 JLabel 对象 private static Thread t; //声明线程对象 private int count = 0; //声明计数变量 private Container container = getContentPane(); //声明容器 public SwingAndThread() { setBounds(300,200,250,100); //绝对定位窗体大小与位置 container.setLayout(null); //使窗体不适用任何布局管理器 URL url = SwingAndThread.class.getResource("1.png"); //获取图片的URL Icon icon = new ImageIcon(url); //实例化一个 Icon jl.setIcon(icon); //将图标放置再标签中 jl.setHorizontalAlignment(SwingConstants.LEFT); //设置图片在标签的最左方 jl.setBounds(10, 10, 200, 50); //设置标签的位置与大小 jl.setOpaque(true); t = new Thread(new Runnable() { //定义匿名内部类,该类实现 Runnable 接口 @Override public void run() { //重写run() 方法 while(count <= 200) { //设置循环条件 jl.setBounds(count, 10, 200, 50); //将标签的横坐标用变量表示 try { Thread.sleep(1000); //将线程休眠 1000 毫秒 }catch (Exception e) { e.printStackTrace(); } count += 30; //使横坐标每次增加4 if(count >= 200) { //当图标到达标签的最右边时,使其回到标签最左边 count=10; } } } }); t.start(); //启动线程 container.add(jl); //将标签添加到容器中 setVisible(true); //设置窗体可见 setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); //设置窗体关闭方式 } public static void main(String[] args) { new SwingAndThread(); //实例化一个 SwingAndThread 对象 // System.out.println(SwingAndThread.class.getResource("")); } }
运行结果(有水印望各位请体谅理解):
注意:这里我要讲解下面这行代码
URL url = SwingAndThread.class.getResource("1.png");
当时我有卡在这里,因为不知道图片放在哪里,getResource() 方法才能获取到。后面百度了下,才找到了解决的方法:
可以看到,我在 main() 方法里注释了一行代码:
System.out.println(SwingAndThread.class.getResource(""));
这行代码,是用来获取当前当前项目的运行路径的。结果为:
所以能够得出,图片肯定放在bin目录下才能获取到。
总结:
- run() 方法用来存放 线程执行逻辑
- 只有调用 start() 方法才会产生线程实体,并且运行。