Luckylau's Blog

Keep Moving, Keep Learning


  • 首页

  • 分类

  • 关于

  • 归档

  • 标签

  • 搜索
close
Luckylau's Blog

Java并发之线程的理解

发表于 2017-05-26 | 分类于 java

并发的理解

​ 对于一个CPU来说,无论我创建多少个线程,所谓的“并发执行”、“同时”其实都不是真正意义上的“同时”。操作系统将进程线程进行管理,轮流(没有固定的顺序)分配每个进程很短的一段时间(不一定是均分),然后在每个线程内部,程序代码自己处理该进程内部线程的时间分配,多个线程之间相互的切换去执行,这个切换时间也是非常短的。因此多任务、多进程、多线程都是操作系统给人的一种宏观感受,从微观角度看,程序的运行是异步执行的。虽然操作系统是多线程的,但CPU每一时刻只能做一件事。另外上下文开销是多线程面临的主要问题,可以通过无锁并发编程、CAS算法、使用最少线程和使用协程的方式解决。

线程和进程的区别

1,每个进程都有独立的代码和数据空间,进程间的切换会有较大的开销;
2,线程可以看成是轻量级的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器,线程切换的开销小;
3,多进程:在操作系统中能同时运行多个任务(程序);
4,多线程:在同一应用程序中有多个顺序流同时执行;

参考可见:线程与进程的区别

线程的实现

实现线程主要有3种方式:使用内核线程实现、 使用用户线程实现和使用用户线程加轻量级进程混合实现。

使用内核线程实现

​ 内核线程(Kernel-Level Thread,KLT)就是直接由操作系统内核(Kernel,下称内核)支持的线程,这种线程由内核来完成线程切换,内核通过操纵调度器(Scheduler)对线程进行调度,并负责将线程的任务映射到各个处理器上。 每个内核线程可以视为内核的一个分身,这样操作系统就有能力同时处理多件事情,支持多线程的内核就叫做多线程内核(MultiThreads Kernel)。由于内核线程的支持,每个轻量级进程都成为一个独立的调度单元,即使有一个轻量级进程在系统调用中阻塞了,也不会影响整个进程继续工作,但是轻量级进程具有它的局限性:首先,由于是基于内核线程实现的,所以各种线程操作,如创建、 析构及同步,都需要进行系统调用。 而系统调用的代价相对较高,需要在用户态(User Mode)和内核态(KernelMode)中来回切换。 其次,每个轻量级进程都需要有一个内核线程的支持,因此轻量级进程要消耗一定的内核资源(如内核线程的栈空间),因此一个系统支持轻量级进程的数量是有限的。

使用用户线程实现

​ 从广义上来讲,一个线程只要不是内核线程,就可以认为是用户线程(User Thread,UT),因此,从这个定义上来讲,轻量级进程也属于用户线程,但轻量级进程的实现始终是建立在内核之上的,许多操作都要进行系统调用,效率会受到限制。而狭义上的用户线程指的是完全建立在用户空间的线程库上,系统内核不能感知线程存在的实现。 用户线程的建立、 同步、 销毁和调度完全在用户态中完成,不需要内核的帮助。如果程序实现得当,这种线程不需要切换到内核态,因此操作可以是非常快速且低消耗的,也可以支持规模更大的线程数量,部分高性能数据库中的多线程就是由用户线程实现的。

​ 使用用户线程的优势在于不需要系统内核支援,劣势也在于没有系统内核的支援,所有的线程操作都需要用户程序自己处理。 线程的创建、 切换和调度都是需要考虑的问题,而且由于操作系统只把处理器资源分配到进程,那诸如“阻塞如何处理”、 “多处理器系统中如何将线程映射到其他处理器上”这类问题解决起来将会异常困难,甚至不可能完成。 因而使用用户线程实现的程序一般都比较复杂,除了以前在不支持多线程的操作系统中(如DOS)的多线程程序与少数有特殊需求的程序外,现在使用用户线程的程序越来越少了,Java、Ruby等语言都曾经使用过用户线程,最终又都放弃使用它。

使用用户线程加轻量级进程混合实现

​ 用户线程还是完全建立在用户空间中,因此用户线程的创建、 切换、 析构等操作依然廉价,并且可以支持大规模的用户线程并发。 而操作系统提供支持的轻量级进程则作为用户线程和内核线程之间的桥梁,这样可以使用内核提供的线程调度功能及处理器映射,并且用户线程的系统调用要通过轻量级线程来完成,大大降低了整个进程被完全阻塞的风险。

线程的状态

线程的创建

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Calculator implements Runnable {
private int number;
public Calculator(int number){
this.number = number;
}
@Override
public void run() {
// TODO Auto-generated method stub
for (int i=1; i<=10; i++){
System.out.printf("%s: %d * %d = %d\n",Thread.currentThread().getName(),number,i,i*number);
}
}
}
1
2
3
4
5
6
7
8
9
public class Main {
public static void main(String[] args) {
for (int i=1; i<=2; i++){
Calculator calculator=new Calculator(i);
Thread thread=new Thread(calculator);
thread.start();
}
}
}
阅读全文 »
Luckylau's Blog

Java虚拟机之理解Java虚拟机的含义

发表于 2017-05-26 | 分类于 java

什么是Java虚拟机

从外部行为和功能理解Java虚拟机:

​ 虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机有自己完善的硬体架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。JVM屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。,简而言之,屏蔽底层操作系统平台的不同并且减少基于原生语言开发的复杂性,使java这门语言能够跨各种平台(只要虚拟机厂商在特定平台上实现了虚拟机),并且简单易用。

从操作系统进程理解Java虚拟机:

​ 虚拟机是运行在操作系统之中的,那么什么东西才能在操作系统中运行呢?当然是进程,因为进程是操作系统中的执行单位。可以这样理解,当它在运行的时候,它就是一个操作系统中的进程实例,当它没有在运行时(作为可执行文件存放于文件系统中),可以把它叫做程序。

阅读全文 »
Luckylau's Blog

Java基础之equals,== 和 hashcode理解

发表于 2017-05-24 | 分类于 java

equals ,== 和 hashcode的理解

Object类是类继承结构的基础,所以是每一个类的父类。所有的对象,包括数组,都实现了在Object类中定义的方法。

java.lang.Object类中有两个非常重要的方法:

public boolean equals(Object obj)

public int hashCode()

==与equals的关系?

== 是比较引用是否相等。上面我们说过equals是Object类的重要方法之一,是用来判断其他的对象是否和该对象相等。

equals()方法在object类中定义如下:

1
2
3
public boolean equals(Object obj) {
return (this == obj);
}
阅读全文 »
Luckylau's Blog

Java基础之String分析

发表于 2017-05-19 | 分类于 java

String的源码分析

从一段代码说起

1
2
3
4
5
6
7
8
9
10
public class StringDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
String a = "abc";
String b = "a" + "b" + "c";
System.out.println(a == b); //true
String c = new String("abc");
System.out.println(a == c); //false
}
}

下面我们从源码看String的具体实现(本文是jdk1.8)。

String的初始化

String类的属性包含一个不可变的char数组用来存放字符串,一个int型的变量hash用来存放计算后的哈希值

阅读全文 »
Luckylau's Blog

Java基础之克隆机制

发表于 2017-05-19 | 分类于 java

java的克隆机制

Java中对象的创建

使用new操作符创建一个对象

​ new操作符的本意是分配内存。程序执行到new操作符时, 首先去看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数,填充对象的各个域,这一步叫做对象的初始化,构造方法返回后,一个对象创建完毕,可以把他的引用(地址)发布到外部,在外部就可以使用这个引用操纵这个对象。

使用clone方法复制一个对象

​ clone在第一步是和new相似的, 都是分配内存,调用clone方法时,分配的内存和源对象(即调用clone方法的对象)相同,然后再使用原对象中对应的各个域,填充新对象的域, 填充完成之后,clone方法返回,一个新的相同的对象被创建,同样可以把这个新对象的引用发布到外部。

使用序列化的方式克隆一个对象

​ 把母对象写入到一个字节流中,再从字节流中将其读出来,这样就可以创建一个新的对象了,并且该新对象与母对象之间并不存在引用共享的问题,真正实现对象的深拷贝。

Clone()方法的延伸思考

复制对象 or 复制引用

阅读全文 »
Luckylau's Blog

Java基础之集合框架

发表于 2017-05-16 | 分类于 java

java的集合框架详细解读(基于jdk1.8)

java集合框架

java集合框架需要掌握的是六大接口(Collection、Set、List、Map、Iterator和Comparable)和两个工具类Arrays和Collections。

Collection接口继承了Iterable接口,是最基本集合接口,由于Iterable接口依赖Iterator接口,所以所有实现Collection接口的容器类都有iterator方法,用于返回一个实现了Iterator接口的对象。Iterator对象称作迭代器,Iterator接口方法能以迭代方式逐个访问集合中各个元素,并可以从Collection中除去适当的元素。另外由Collection接口派生出3个主要接口,分别是List ,Set,Queue。

Map也是接口,但没有继承Collection接口。该接口描述了从不重复的键到值的映射。Map接口用于维护键/值对(key/value pairs)。

Comparable可以用于比较的实现,实现了Comparable接口的类可以通过实现comparaTo方法从而确定该类对象的排序方式。

阅读全文 »
1…252627…36
Luckylau

Luckylau

人生识字忧患始

215 日志
14 分类
33 标签
GitHub Weibo
© 2017 - 2022 Luckylau
由 Hexo 强力驱动
主题 - NexT.Pisces