1、什么是进程、线程、多线程?
进程当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。进程间通讯依靠IPC资源,例如管道、套接字
线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码是共享的,即不同的线程可以执行同样的函数。
多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说说允许单个程序创建多个并行执行的线程来完成各自的任务。线程间通讯依靠JVM提供的API,例如wait()、notify、notifyAll等方法,线程间还可以通过共享的主内存来进行值的传递
2、多线程的优缺点?
优点:可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其他的线程而不是等待,提高程序相应效率。
缺点:线程也是程序,所有线程需要占用内存,线程越多占用的内存也越多。
线程需要协调和管理,所以需要CPU时间跟踪线程
线程之间对共享资源的访问会互相影响,必须要解决竞用共享资源的问题
线程太多会导致控制太复杂,最终可能造成很多Bug
3、多线程一定比单线程快吗?
不一定,由于多线程会存在线程上下文切换,会导致程序执行速度变慢,但可以充分利用CPU,所以对于用户来说,可以减少用户响应时间。
比如,尝试使用并行和串行分别执行累加的操作观察是否并行执行一定比串行更快:
package com.test.demo; public class Tester { private static final long count = 1000000000; public static void bingxing() throws Exception { long startTime = System.currentTimeMillis(); //通过匿名内部类来创建线程 Thread thread1 = new Thread(new Runnable() { @Override public void run() { int a = 0; for(long i = 0; i < count; i++) { a += 1; } } }); Thread thread2 = new Thread(new Runnable() { @Override public void run() { int b = 0; for(long k = 0;k < count; k++) { b+=1; } } }); //启动线程 thread1.start(); thread2.start(); //等待线程结束 thread1.join(); thread2.join(); long time = System.currentTimeMillis() - startTime ; System.out.println("并行花费时长:" + time + "ms"); } public static void chuanxing() { long startTime = System.currentTimeMillis(); int a = 0; for(long i = 0; i < count; i++) { a += i; } int b = 0; for(long k = 0;k < count; k++) { b+=k; } long time = System.currentTimeMillis() - startTime ; System.out.println("串行花费时长:" + time + "ms"); } public static void main(String[] args) throws Exception { bingxing(); chuanxing(); } }
循环次数 | 串行执行/ms | 并行执行/ms | 结果 |
1千 | 0ms | 2ms | 慢 |
1万 | 0ms | 2ms | 慢 |
10万 | 3ms | 4ms | 慢 |
100万 | 6ms | 4ms | 快 |
1000万 | 13ms | 11ms | 快 |
1亿 | 89ms | 78ms | 快 |
从测试结果看出当超过100万次循环后,并行执行的优势越加明显,不超过100万次循环时,串行执行的速率要比并行执行的速率高,原因就是多线程有上下文切换的开销。
4、阻塞与非阻塞
阻塞和非阻塞通常用来形容多线程之间的相互影响
阻塞是指一个线程占用了临界区资源,那么其他所有需要这个资源的线程就不洗在这个临界区中进行等待,等待会导致线程挂起,这种情况就是阻塞
非阻塞强调没有一个线程可以妨碍其他线程执行,所有线程都会尝试不断向前执行
5、临界区
临界区用来表示一种公共资源或者共享资源可以被多个线程使用,但是每一次只能有一个线程使用它,一旦临界区资源被占用,其他线程想要使用这个资源,就必须等待
6、死锁Deadlock、饥饿starvation、活锁Livelock
死锁表示两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们将无法推进下去,此时称系统处于死锁状态,这些永远在互相等待的进程成为死锁进程
饥饿表示一个或者多个线程应为种种原因无法获得所需要的资源,导致一直无法执行。导致饥饿的原因可能是该线程优先级太低,而高优先级的线程不但抢占它所需要的资源,导致其无法向前推进,另外一种可能是,某线程一直占着关键资源不放,导致其他需要这个资源的线程无法正常执行
活锁表示两个或者多个线程主动将资源释放给其他线程,导致没有一个线程可以同时拿到所有资源而正常执行。
7、如何避免死锁
指定获取锁的顺序
原文:https://www.cnblogs.com/conswin/p/10384921.html