多线程基础
Posted CODE阿宝
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程基础相关的知识,希望对你有一定的参考价值。
1、同步和异步
比如执行两个方法,同步是指第1个方法执行完返回结果再继续执行第2个方法;而异步是指方法执行不等其结果,另一个方法相继执行,所以结果返回有延迟(ajax调用)
同步特点:保证方法有序的执行,缺点响应慢
异步特点:响应速度快,但不能保证结果有序的执行,如方法1执行时,结果还未返回,方法2已经执行,如果此是需要用方法1的结果作为参数去执行方法2,那么可能程序会报错
2、并发(单个CPU)和并行(多个CPU) 但因CPU执行速度很快,看似都在同时进行,所以一般不作区分
3、临界区 多线程共同访问的共享资源,存在线程安全,所以这个区域需要同步控制
4、阻塞(blocking) 线程挂起
非阻塞(non-blocking) 允许多个线程进入临界区
5、死锁(deallock)
/**
* 死锁例子
* 1、两个线程t1,t2 两个资源s1,s2
* 2、t1执行 s1资源(已锁),t1休眠2秒, 锁未释放
* 3、t2执行 s2资源(已锁) ,继续请求s1资源(已锁)
* 4、t1在2秒后继续执行,请求s2资源(已锁)
* 5、结果:t1请求s2资源发现s2资源已锁进入等待状态
* t2请求s1资源发现s1资源已锁进入等待状态
* t1和t2都因等待不能继续执行,进入程序无响应状态
* 避免死锁:一个线程避免多个锁,避免一个线程在锁内同时占多个资源,尝试使用定时锁lock.tryLock(timeout),对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况
*/
public class _1DeadLock {
private static String s1="资源1";
private static String s2="资源2";
public static void main(String[] args) {
new _1DeadLock().deadLock();
}
public void deadLock(){
//线程1
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
synchronized (s1){ //锁资源1
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (s2){
System.out.println("1");
}
}
}
});
//线程2
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
synchronized (s2){
synchronized (s1){
System.out.println("2");
}
}
}
});
t1.start();
t2.start();
}
}
饥饿死锁:在一个线程池中,如果是一个线程要等待另一个线程结束才能执行(换言之依赖另一个线程),但如果此线程因为特殊原因不能正常结束,则这个等待的线程要被饿死,永远不会执行
活锁(livelock) 电梯遇人,门开了,遇到人,里面人和外面人都想避开对方,但是里面人向左,外面人也向左,里面和外面的人都执行相同方向的躲避,结果路一直是堵着
6、并发级别:阻塞4、无障碍3、无锁2、无等待1(所有读线程)
7、并行定律
Amdahl(阿姆达尔定律) 告诉我们CPU数量不是加的越多越好,因为根据这个定律,当CPU数量越多,而步行的步骤是不变的,则加速比会越来越小
比如执行一段程序,需要5步完成,第2步和第5步用到了2个CPU并行计算,则加速比=1/(2/5*1/2+3/5)=1.25
Gustafson(古斯塔夫森定律) 告诉我们只要有足够的并行化,那么加速比和CPU个数成正比
执行时间a+b(a表示串行时间 b表示并行时间) 总执行时间a+nb(n为处理器个数 ) 则加速比S(n)=a+nb/(a+b) 因串行比例F=a/(a+b) 进行推导结果加速比S(n)=n-F(n-1)
8、什么是线程 线程是进程内的执行单元
9、线程操作:
new(创建线程)-----> start(开始线程)----->runnable(执行具体方法) terminated(关闭线程)
synchronized(同步)---->blocked(阻塞线程) wait(等待)---->waiting(等待中)---->notify(唤醒) timed_waiting(有限时间的等待)
10、线程yield和join
Thread.yield() 是一个静态方法,线程让步,让其他线程有机会争夺CPU
t1.join();执行Join方法后,其他线程都进入wait状态,当t1执行完后,在jvm中会调用notifyAll()唤醒其他线程。比如需要t1执行完(比如数据的保存),再执行后面的代码
11、线程的终止
Thread.stop() 不推荐使用,太暴力,会释放所有锁,造成数据的幻读 比如t1正在写数据,写到一半,进行stop,会释放锁,而此是t2就会读到修改了一半数据,造成数据的读取错误
Thread.interrupt() 线程中断
12、sleep 休眠会抛出中断异常,此时会清空中断的标志位,所以要在异常中继续中断操作才能有效
13、suspend(挂起) resume(继续执行) 这两个方法不推荐使用,之所以保留也是向旧版本兼容,因为suspend不会释放锁,多线程resume可能会发生在suspend之前,可能会造成线程冻结状态,永久的挂起,
如果某个线程可能正在等待该线程释放锁,那么会造成死锁
jps查看Java进程,然后 jstack pid dump
14、守护线程(后台线程) setDaemon(true) ;比如垃圾回收等,当主线程结束时,守护线程自然退出
15、线程优先级 t1.setPriority(10); 优先级越高,CPU优先执行该线程
16、线程的同步 synchronized
17、Object.wait(); Object.notify(); 注意使用wait必须该线程要先获得monitor这个监视对象的锁,也就是说必须放在synchronized的同步方法块中
以上是关于多线程基础的主要内容,如果未能解决你的问题,请参考以下文章