一、并发之多线程基础

1、同步和异步
比如执行两个方法,同步是指第1个方法执行完返回结果再继续执行第2个方法;而异步是指方法执行不等其结果,另一个方法相继执行,所以结果返回有延迟(ajax调用)
同步特点:保证方法有序的执行,缺点响应慢
异步特点:响应速度快,但不能保证结果有序的执行,如方法1执行时,结果还未返回,方法2已经执行,如果此是需要用方法1的结果作为参数去执行方法2,那么可能程序会报错
2、并发(单个CPU)和并行(多个CPU) 但因CPU执行速度很快,看似都在同时进行,所以一般不作区分
3、临界区 多线程共同访问的共享资源,存在线程安全,所以这个区域需要同步控制
4、阻塞(blocking) 线程挂起
非阻塞(non-blocking) 允许多个线程进入临界区
5、死锁例子(deallock) 

 1 /**
 2  * 死锁例子
 3  * 1、两个线程t1,t2  两个资源s1,s2
 4  * 2、t1执行  s1资源(已锁),t1休眠2秒, 锁未释放
 5  * 3、t2执行  s2资源(已锁) ,继续请求s1资源(已锁)
 6  * 4、t1在2秒后继续执行,请求s2资源(已锁)
 7  * 5、结果:t1请求s2资源发现s2资源已锁进入等待状态
 8  *          t2请求s1资源发现s1资源已锁进入等待状态
 9  *          t1和t2都因等待不能继续执行,进入程序无响应状态
10  * 避免死锁:一个线程避免多个锁,避免一个线程在锁内同时占多个资源,尝试使用定时锁lock.tryLock(timeout),对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况
11  */
12 
13 public class _1DeadLock {
14     private static String s1="资源1";
15     private static String s2="资源2";
16 
17     public static void main(String[] args) {
18          new _1DeadLock().deadLock();
19     }
20     public void deadLock(){
21         //线程1
22         Thread t1=new Thread(new Runnable() {
23             @Override
24             public void run() {
25                 synchronized (s1){ //锁资源1
26                     try {
27                         Thread.sleep(2000);
28                     } catch (InterruptedException e) {
29                         e.printStackTrace();
30                     }
31                     synchronized (s2){
32                         System.out.println("1");
33                     }
34                 }
35             }
36         });
37         //线程2
38         Thread t2=new Thread(new Runnable() {
39             @Override
40             public void run() {
41                 synchronized (s2){
42                     synchronized (s1){
43                         System.out.println("2");
44                     }
45                 }
46             }
47         });
48         t1.start();
49         t2.start();
50     }
51 }

 


饥饿死锁:在一个线程池中,如果是一个线程要等待另一个线程结束才能执行(换言之依赖另一个线程),但如果此线程因为特殊原因不能正常结束,则这个等待的线程要被饿死,永远不会执行
活锁(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的同步方法块中

posted @ 2018-04-14 10:23  CODE阿宝  阅读(255)  评论(0编辑  收藏  举报