本章主要介绍java中多线程并发编程基础知识,包括的内容有:
1.1 进程、线程和协程
进程是资源分配的最小单位,操作系统会以进程为单位,分配系统资源(CPU时间片、内存等资源)。进程拥有自己独立的堆和栈,既不共享堆,也不共享栈。
线程是CPU调度的最小单位,线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,共享堆不共享栈。
协程是一种比线程更加轻量级的存在,协程不是被操作系统内核所管理,而完全是由程序所控制(也就是在用户态执行)。这样带来的好处就是性能得到了很大的提升,不会像线程切换那样消耗资源。
【区别】
【联系】
与多线程相比,协程具有的优势特点是:
1.2 并行和并发:
并行是时间上各不影响的同时执行,而并发在时间上是相互应用时间片段,宏观上看是并行的。
1.3 阻塞和非阻塞:
形容多线程之间的相互影响,当一个线程独占临街资源时,其他线程需要等待,导致线程挂起,这就是阻塞。
1.4 临界区:
表示一种公共资源,可以被多个线程使用,但是每次只允许一个线程独占。
1.5 死锁、活锁
死锁:指两个或多个线程在执行的过程中,由于资源相互竞争造成阻塞的现象。若无相关操作,他们将被无限期阻塞下去。死锁是一个静态问题,进程会被卡死,但是不会占用cpu。
活锁:是一个动态过程,比如:线程A、B都需要临界资源a和临界资源b,线程A占用a,需要b,线程B占用b,需要a,放弃了资源以后,A又获得了b资源,B又获得了a资源,如此反复,则发生了活锁。
1.6 饥饿:
指某一个或者多个线程因为种种原因无法获得所需要的资源,导致一直无法执行。
创建多线程,可以通过以下几种方式:
3.1 线程的优先级
java 中线程默认的优先级有10级,MAX_PRIORITY和MIN_PRIORITY分别是最高级10和最低级1,当然还有默认级别是5;线程优先级的一些特性:
可以通过Thread.setPriority(level)来实现对线程优先级的控制。
java 中有两种线程:用户线程和守护线程,可以通过isDaemon()方法来区别它们:如果返回false,则说明该线程是“用户线程”;否则就是“守护线程”。
当Java虚拟机启动时,通常有一个单一的非守护线程(该线程通过是通过main()方法启动)。JVM会一直运行直到下面的任意一个条件发生,JVM就会终止运行:
(01) 调用了exit()方法,并且exit()有权限被正常执行。
(02) 所有的“非守护线程”都死了(即JVM中仅仅只有“守护线程”)。
每一个线程都被标记为“守护线程”或“用户线程”。当只有守护线程运行时,JVM会自动退出。
3.2 线程的中断
线程中断:中断是一种协作机制,调用线程的interrupt方法不一定会中断正在运行的线程,它会要求线程在合适的时机结束自己。每个线程都会有一个boolean的中断状态,interrupt方法只是将状态设置为true,对于非阻塞的线程,只是状态进行了改变,并不一定会立即停止。如果线程上使用了Thread.sleep(), Object.wait(), Thread.join(),这个线程收到中断信号后, 会抛出InterruptedException, 同时会把中断状态置回为false。
Thread.stop():会释放掉所有的监管monitor,无论线程执行到哪里,都会立即停止线程,不推荐使用。
wait和notify区别
共同点:
1)都是在多线程的环境下,都可以在程序的调用处阻塞指定的毫秒数,并返回。
2)wait()和sleep()都可以通过interrupt()方法 打断线程的暂停状态 ,从而使线程立刻抛出InterruptedException。
不同点:
1)sleep和yield方法都是Thread类方法,wait和notify,notifyAll都是object的方法;
2)sleep睡眠时,保持对象锁,仍然占有该锁;而wait睡眠时,释放对象锁。
3)sleep可以在任何地方使用,并且需要捕获编译异常;wait和notify,notifyAll需要在同步块中使用。
1)新建状态:被new()出来
2)runnable状态:线程start
3)running状态:线程获得时间片,正执行
4)等待状态:线程被wait,释放掉锁的状态
5)等锁状态:线程被notify后,进入等锁池
6)阻塞状态:线程sleep,join或者Io阻塞
7)dead:线程执行完
线程之间的扭转关系可有:
Java语言中有一个“先行发生”(happen—before)的规则,它是Java内存模型中定义的两项操作之间的偏序关系。Java内存模型中的八条可保证happen—before的规则,它们无需任何同步器协助就已经存在。
public class HappenBeforeTest extends Thread {
private boolean flag;
@Override
public void run(){
while(!flag){
System.out.println("thread run");
}
System.out.println("thread stop");
}
public boolean getStop(){
flag = true;
return flag;
}
public static void main(String[] args) throws InterruptedException {
HappenBeforeTest test = new HappenBeforeTest();
test.start();
Thread.sleep(1000);
test.getStop();
Thread.sleep(1000);
}
}
这个程序在client模式下能够正常的打印thread run和thread stop。但是在Server模式下可能将是无限循环。因为虽然getStop函数设定了结束标识,但是线程不一定能取到值,甚至会运行抛出异常。
参考文献:进程、线程和协程之间的区别和联系_~青萍之末~的博客-CSDN博客_进程线程协程
参考文献:http://www.cnblogs.com/GarfieldEr007/p/5746362.html