并发
生活中的并发:
在一个时间段内同时做好多件事情
例如:人体可以同时进行呼吸,血液循环,思考问题等,在走路的同时还可以唱歌,等等
计算机中的并发:
在使用Eclipse的同时还可以放音乐,可以同时运行多个程序。
并发原理
世间万物都可以同时完成很多工作,可能生活中是真的并发存在的,在同一个时间段内可以同时做好几件事情,但是在程序里面,没有真正意义上的同时发生,“同时”运行只是我们感官上的一种表现,事实上线程是并发运行的,OS将时间划分为很多片段(时间片)尽可能均匀的分配给每一个线程,获取时间片段的线程被CPU运行,而其他线程全部等待,所以微观上是走走停停的,宏观上都在运行,这种现象叫做“并发”,但是绝不是意义上的“同时发生”。
只不过CPU在运行的时候太快了,在宏观上给人的感觉是在一起运行,但其实不是,就像是那个淘宝客服,如果他打字的速度够快,那么就可以同时服务好几个人,CPU也是一样的,如果有好多个任务要处理,他处理的时候是这个处理一点,那个处理一点,由于太快了,所以宏观上给人的感觉是同时处理的,其实不是.
Java语言提供了并发机制,程序员可以在程序中执行多个线程,每一个线程完成一个功能,并与其他线程并发执行,这种机制被称之为是多线程。
例如我们在玩某个游戏时,在游戏中我们会听到某些背景音乐,某个角色在移动,出现某些绚丽的动画效果等,这些在游戏中都是同时发生的,但实际上,播放音乐是在一个线程中独立完成的,移动某个角色,播放某些特效也都是在独立的线程中完成的。
什么是进程
Windows操作系统是多任务操作系统,以进程为单位,一个进程是一个包含有自身地址的程序,每个独立执行的程序都称之为是进程,也就是正在执行的程序。系统可以分配给每一个进程一段有限的使用CPU的时间,也可以称之为是CPU时间片,CPU在这段时间中执行某个进程,然后下一个时间片又跳到另一个进程中去执行,由于CPU转换较快,所以使得每个进程好像是同时执行一样。
什么是线程
线程是进程中的任务执行序列,一个正在运行的程序就是一个进程,那么这个程序里正在做的事情就是一个线程.所以线程是进程的一部分。
比如:正在运行的eclipse是一个进程.而我们通过Eclipse运行一个main方法这就是一个线程,所以说白了所谓的线程就是一个正在运行的进程中的一个小任务。
什么是多线程
一个进程中可以同时包括多个线程,每个线程也可以得到一小段程序的执行时间,这样一个进程就可以具有多个并发执行的线程。
比如我用百度网盘同时下载多个视频的时候,每一个正在下载的视频,都是一个线程,线程是进程的一部分,一个进程可以包含n个线程。
一个进程至少有一个线程。线程的划分尺度小于进程,使得多线程程序的并发性高。另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
线程不能独立存在,必须依附于进程.
进程与线程的区别
一个进程至少有一个线程。线程的划分尺度小于进程,使得多线程程序的并发性高。另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
线程在执行过程中与进程的区别在于每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用来实现进程的调度和管理以及资源分配。
Java中的多线程
Java语言提供了并发机制,程序员可以在程序中执行多个线程,每一个线程完成一个功能,并与其他线程并发执行,这种机制被称之为是多线程。
多线程的意义
多线程的存在,不是提高程序的执行速度,其实是为了提高应用程序的使用率。
程序的执行其实就是在抢占CPU的资源
我们不能保证每一个进程或者每一个线程在每时每刻抢到,所以线程的执行有随机性。
Java程序的运行原理
java 命令会启动 java 虚拟机,启动 JVM,等于启动了一个应用程序,也就是启动了一个进程。
该进程会自动启动一个 “主线程” ,然后主线程去调用某个类的 main 方法。所以 main方法运行在主线程中。
问题:jvm虚拟机的启动是单线程的还是多线程的?
答:多线程的。
原因是垃圾回收线程也要先启动,否则很容易会出现内存溢出。
现在的垃圾回收线程加上前面的主线程,最少启动了两个线程,所以,jvm的启动其实是多线程的。
创建多线程的两种方式
在Java中主要提供了两种方式实现线程
继承java.lang.Thread类
实现java.lang.Runnable接口
继承Thread类创建线程类
Thread类是java.lang包中的线程类,从这个类中实例化的对象代表线程,程序员启动一个新线程需要创建Thread实例。
通过继承Thread类来创建并启动多线程的步骤如下
定义Thread类的子类,并且重写该类的run()方法,run()方法的方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体
创建Thread子类的实例,也就是创建Thread对象
调用线程对象的start()方法来启动该线程


优点
使用继承Thread类创建线程的方式的优点在于创建简单,适合使用匿名内部类形式创建
缺点
继承冲突,由于Java是单继承的,这会导致继承Thread就无法再继承其他类了,这在实际开发会是很不方便的。
重写run方法相当于直接将线程执行的任务写死在线程中,导致线程与任务有一个必然的耦合关系,不利于线程的重用。
使用Runnable接口创建线程类
为了避免Java单继承的局限性,所以除了可以继承Thread类之外还可以实现于Runnable接口
实现Runnable接口的程序会创建一个Thread对象,并将Runnable对象与Thread的对象相关联,Thread类中有以下两个构造方法
1、public Thread(Runnable target)
2、public Thread(Runnable target,String name)
这两个构造方法的参数中都存在Runnable实例,使用以上构造方法就可以将Runnable实例与Thread类相关联class。
实现Runnable接口来创建并启动多线程的步骤如下:


说明:在多线程启动的时候,需要先通过Thread类的构造方法Thread(Runnable target)构造出对象,然后调用Thread对象的start()方法来运行多线程代码
实际上所有的多线程代码都是通过运行Thread的start()方法来运行的,因此,不管是扩展Thread类还是实现Runnable接口来实现多线程,最终还是通过Thread对象的API来控制线程。
使用内部类创建线程
通常我们可以通过匿名内部类的方式创建线程,使用该方式可以简化编写代码的复杂度,当一个线程仅需要一个实例时我们通常使用这种方式来创建。

线程API
Thread.currentThread方法
Thread的静态方法currentThread方法可以用于获取运行当前代码片段的线程。
获取线程信息
Thread提供了 获取线程信息的相关方法:
long getId():返回该线程的标识符
String getName():返回该线程的名称
int getPriority():返回线程的优先级
Thread.state getState():获取线程的状态
boolean isAlive():测试线程是否处于活动状态
boolean isDaemon():测试线程是否为守护线程
boolean isInterrupted():测试线程是否已经中断
线程优先级
设置优先级的方法为:
线程的生命周期
当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态,在线程的生命周期中,它需要经过创建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)这5种状态,当线程启动以后,它不可能一直“霸占”这CPU独自运行,所以CPU需要在多条线程之间切换,于是线程状态也会在就绪Runnable状态和运行running阶段之间切换。

线程并发安全
当多个线程的并发对同一个临界资源操作时,可能由于线程切换时机不确定导致程序和设计的执行方式出现混乱,甚至程序瘫痪.
synchronized关键字
多个线程并发读写同一个临界资源时候会发生"线程并发安全问题“
常见的临界资源:
若想解决线程安全问题,需要将异步的操作变为同步操作。 何为同步?那么我们来对比看一下什么是同步什么异步。
所谓异步操作是指多线程并发的操作,相当于各干各的。
所谓同步操作是指有先后顺序的操作,相当于你干完我再干。
而java中有一个关键字名为:synchronized,该关键字是同步锁,用于将某段代码变为同步操作,从而解决线程并发安全问题。

标签: