并发编程之多线程基础-Thread和Runnable的区别及联系(二)
上篇文章讲述了创建线程的常用方式
本篇主要分析一下Thread和Runnable两种方式创建线程的区别及联系
联系:
▶Thread类实现了Runable接口。
▶都需要重写里面Run方法。
区别:
▶Thread方式不支持多继承,Runnable方式支持多个实现
▶Runnable更容易实现资源共享,能多个线程同时处理一个资源。
疑惑分享:
本人在理解他们区别的时候
考虑到Thread类本身就是Runnable的实现类
所以产生了一个疑惑:-
为什么Runnable可以实现共享而Thread却不行呢
疑惑代码:
class Thread1 extends Thread {
int i = 100;
@Override
public void run() {
while (i > 0) {
try {
Thread.sleep(40L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (this) {
/*synchronized 不要直接放在run方法 应该放到循环里面 这样多个线程在循环的时候每次都能竞争锁 从而实现交替执行 否则一个线程执行完了另一个线程就没有执行的机会了*/
if (i > 0) {
/*
1.加判断是为了 如果当i=1的时候 此时两个线程都执行到了这里 一个线程得到锁进行减一操作那么i变为0 此时第二个线程再输出就会把0输出出来
2.第二个线程能够及时读取到i的值是由于synchronized既可以实现原子性又可以实现可见性*/
System.out.println(Thread.currentThread().getName() + "i:" + i);
i--;}}}
}}
public class TestThread {
public static void main(String[] args) {
Thread1 te1 = new Thread1();
Thread t1 = new Thread(te1, "window1");
Thread t2 = new Thread(te1, "window2");
t1.start();
t2.start();
}
}
下面我们就来聊一聊(有共同疑惑的朋友们可以参考一下):
首先我们要清楚Thread和Runnable两种方式的本质区别在哪里
我们知道无论使用哪种方式最终都会通过 Thread类对象调用start方法进行开启线程
本质的区别就在于:
Thread方式是调用无参构造方法
Runnable方式是调用带有Runnable参数的有参构造方法
我们说过Thread类实现了Runable接口
以上疑惑代码中就是向Thread构造方法中传递了一个Tel1参数
看似与Runnable没有关系
但实质上是属于常说的Runnable方式调用
对应源码:Thread(Runnable target, String name)
那么有参和无参有什么区别是什么呢,为什么runnable能实现资源共享:
参考源码:
this.target = paramRunnable;
public void run()
{
if (this.target != null)
this.target.run();
}
有参:
如果是参数中Runnable不为空
那么Thread run方法中最终执行的方法实际上是传进来Runnable中的run方法
所以使用Runnable方式 无论new出多少个Thread对象
最终执行的任务都是一样的
自然就实现了资源的共享
无参:
每次new出Thread对象
他们对应的成员变量是互不影响的
所以就不能达到资源共享的效果
涉及知识点:
JMM关于synchronized的两条规定:
1)线程解锁前,必须把共享变量的最新值刷新到主内存中
2)线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新获取最新的值
(注意:加锁与解锁需要是同一把锁)
通过以上两点,可以看到synchronized能够实现可见性。同时,由于synchronized具有同步锁,所以它也具有原子性
温馨提示:
▶在学习过程中理解一些概念或者结论不清晰的时候,一定要亲自动手结合着代码去分析,不要片面的理解一些知识点,一定要搞清实质。
▶本文内容如有不妥,恳请指正。
相关文章
- 使用Commons Logging
- 记一次 .NET 某自动化采集软件 崩溃分析
- [C# 中的序列化与反序列化](.NET 源码学习)
- .NET 向量类型的运算结果范例——用于学习Vector类所提供百多个向量方法
- 树莓派(香橙派)通过.NET IoT 操作SPI编写屏幕驱动 顺手做个四足机器人(一)
- WPF自定义控件之消息提示
- .NET跨平台框架选择之一 - Avalonia UI
- 篇(16)-Asp.Net Core入门实战-权限管理之用户创建与关联角色(ViewModel再用与模型验证二)
- 学习ASP.NET Core Blazor编程系列十——路由(下)
- 代码生成器(CodeBuilder) 2.9.4 稳定版
- 篇(15)-入门实战-权限管理之用户创建与关联角色(ViewModel再用与模型验证一)
- 篇(14)-Asp.Net Core入门实战-权限管理之角色编辑和赋权(ViewModel-DTO初探)
- 算法-2 选择排序、冒泡排序、插入排序
- 篇(13)-Asp.Net Core入门实战-将功能代码增加异步功能Async和配置简单防范CSRF攻击
- NET 6 实现滑动验证码(一)、创建工程
- 算法-1 算法复杂度
- 在WPF中使用Prism弹出自定义窗体样式的对话框
- 使用Fody时,CS-SCRIPT动态代码无法找到程序集
- C# 使用SIMD向量类型加速浮点数组求和运算(3):循环展开
- aspnetcore两种上传图片(文件)的方式