赞
踩
/* Thread.start() 方法中调用了原生的start0()方法 */ public synchronized void start() { if (threadStatus != 0) throw new IllegalThreadStateException(); group.add(this); boolean started = false; try { start0(); started = true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { } } } // 原生方法 private native void start0();
解析每一个部件的功能,具体的细节不展开
理解:程序,进程,线程
举例:比如我现在点击了WX.exe的程序,计算机会将WX程序加载到内存,这是在内存中的就是一个WX进程,每一个进程都有一个main线程,ALU找到main线程开始执行
程序:就是一段待执行的代码
进程:将程序这段代码以及所需要的数据加载到内存
线程:CPU,调度的基本单位
再来理解一个常识性的问题:我们买的电脑几核几线程的概念
我们可以通过cmd的命令查看一下自己的电脑(华为matebookpro)
以我自己的电脑为例 四核八线程
wmic
获取cpu的名称 cpu get name
获取cpu的核心数 cpu get numberofcores
也可以通过更加直观的方式, 打开任务管理器
可以很直观的看出有一个插槽,四个内核,八个逻辑处理器
解释
一个插槽说明只有一个物理cpu
四个内核说明有四个ALU
八个逻辑处理器说明每个ALU可以在Register中切换,可以减少线程的挂起
以前的cpu没有使用多核和超线程技术,也就意味着一个物理cpu对应一个内核对应一个线程,效率是极其低下的
什么是线程安全?
要想理解原子性首先要理解几个概念
竞态条件:
专业术语:由于不恰当的执行顺序而出现不正确的结果的这种情况
个人理解:线程由于cpu的调度,多个线程交替执行,要得到正确的结果需要运气成分
// 比如在单例模式中
if (instance == null) {
instance = new Singletion();
}
//这个过程是 先检查再执行,这个过程是可以被cpu打断的
先检查再执行就是一个竞态条件
//比如 count++
//count++ 不是一步执行完成的
需要先从内存中读取,在做修改,在写回内存
读取 - 修改 - 写入 也是一个竞态条件
复合条件:
数据竞争:
加锁机制
加锁机制可以保证原子性,也就是把一系列的操作变为原子的
内置锁
内置锁其实很简单,就是改变了,对象里的markword
// 使用这个依赖可以查看对象的结构
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.10</version>
</dependency>
public class JustTest {
private static class T {
int i;
}
// 不加synchronized
public static void main(String[] args) {
T t = new T();
// 打印对象的结构
System.out.println(ClassLayout.parseInstance(t).toPrintable());
}
}
public class JustTest {
private static class T {
int i;
}
public static void main(String[] args) {
T t = new T();
synchronized (t) {
System.out.println(ClassLayout.parseInstance(t).toPrintable());
}
}
}
重入锁
当一个线程请求一个未被持有锁的对象,JVM会记下所得持有者,并将计数器加一,若果同一线程再次获取锁,则计数器再加一,直到计数器的个数为0时被释放
如果不可重入,下面的代码可能就会死锁
// 父类持有锁,不能释放,而子类需要锁,二者僵持
public class Widget {
public synchronized void doSomething() {
}
}
class LoggingWidget extends Widget {
@Override
public synchronized void doSomething() {
System.out.println(toString());
super.doSomething();
}
}
注:不是所有的数据都需要锁来保护,只有被多个线程同时访问的可变数据才需要通过锁来保护。
活跃性和性能
活跃性:安全性的含义:永远不要发生糟糕的事情,而活跃性则关注于:某个事情最终会发生,但由于如此,就可能出现没有得到锁而死等的现象,或者无意中造成的无限循环
性能:性能方面有很多问题例如,服务时间过长,响应不及时等,要在性能和安全编码之间相互的权衡,不要一味为了性能而去修改简单的并发程序
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。