Thread和Runnable的区别
1. 首先是使用上的区别,先看代码:
class MyThread extends Thread { @Override public void run() { System.out.println("do things"); } } class MyRunnable implements Runnable { @Override public void run() { System.out.println("do things"); } }
可以看到使用Thread是继承关系,而使用Runnable是实现关系。我们知道java不支持多继承,如果要实现多继承就得要用implements,所以使用上Runnable更加的灵活
2. 关于共享数据的问题
Runnable是可以共享数据的,多个Thread可以同时加载一个Runnable,当各自Thread获得CPU时间片的时候开始运行runnable,runnable里面的资源是被共享的
这里用实例来讲解:
首先分别定义一个thread和一个runnable,things这个变量即为所想要共享的资源
class MyThread extends Thread { int things = 5; @Override public void run() { while(things > 0) { System.out.println(currentThread().getName() + " things:" + things); things--; } } } class MyRunnable implements Runnable { String name; public MyRunnable(String name) { this.name = name; } int things = 5; @Override public void run() { while(things > 0) { things--;
System.out.println(name + " things:" + things); } } }
随后,用三个Thread来运行看:
public class ThreadTest { /** * @param args */ public static void main(String[] args) { MyThread thread1 = new MyThread(); MyThread thread2 = new MyThread(); MyThread thread3 = new MyThread(); thread1.start(); thread2.start(); thread3.start(); } }
结果如下:
Thread-0 things:5 Thread-0 things:4 Thread-2 things:5 Thread-1 things:5 Thread-1 things:4 Thread-1 things:3 Thread-1 things:2 Thread-1 things:1 Thread-2 things:4 Thread-2 things:3 Thread-2 things:2 Thread-2 things:1 Thread-0 things:3 Thread-0 things:2 Thread-0 things:1
可以看到每个Thread都是5个things,所以资源是不共享的
下面用一个Runnable在3个Thread中加载尝试看看:
public class ThreadTest { /** * @param args */ public static void main(String[] args) { MyRunnable run = new MyRunnable("run"); Thread th1 = new Thread(run, "Thread 1"); Thread th2 = new Thread(run, "Thread 2"); Thread th3 = new Thread(run, "Thread 3"); th1.start(); th2.start(); th3.start(); } }
结果如下:
run things:3 run things:2 run things:1 run things:0 run things:3
一共打印出了5次,表示things资源使用了5次
3、线程Thread的5状态
创建:执行new方法创建对象,即进入创建状态
就绪:创建对象后,执行start方法,即被加入线程队列中等待获取CPU资源,这个时候即为就绪状态
运行:CPU腾出时间片,该thread获取了CPU资源开始运行run方法中的代码,即进入了运行状态
阻塞:如果在run方法中执行了sleep方法,或者调用了thread的wait/join方法,即意味着放弃CPU资源而进入阻塞状态,但是还没有运行完毕,带重新获取CPU资源后,重新进入就绪状态
停止:一般停止线程有两种方式:1执行完毕run方法,2调用stop方法,后者不推荐使用。可以在run方法中循环检查某个public变量,当想要停止该线程时候,通过thread.para为false即可以将run提前运行完毕,即进入了停止状态
4、线程分类
a. 用户线程,比如主线程,连接网络的线程
b. 守护线程,运行在后台,为用户线程服务 Thread.setDeamon,必须在start方法前调用。守护线程里面不能做一写IO读写的操作。因为当用户线程都结束后,守护线程也会随jvm一起被销毁,如果这个时候守护线程里面还有IO未完成的操作,就会崩溃
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?