一.进程和线程区别:
例如:我们使用的qq就是一个进程,而在这个qq里面有很多的其他功能,例如可以聊天,发送文件,视频,语音,等等,而这些功能就是一个一个线程,而这些线程可以同时的进行,简单来说一个程序有运行时,至少有一个进程,而进程下面可以有多个进程
再举个例子,为什么我在选择电脑的时候,要选择cpu比较高的,就是因为,当我们打开多个软件的时候,而这些,进程会轮流占用cpu,如果你的cpu比较lower的话,就会出现卡机的现象,但是有的人就会问了,为什么我们看不到电脑,切换软件时候cpu状况,因为cpu在切换的时候,非常的快,几乎是每秒的这样,我们用肉眼是很难看清楚的。
二、多线程:
1、什么是多线程:在我的理解多线程就是一个程序中可以有多个同时在进行的任务。
多线程的优势:我举个例子,当我们在网站上面买一个东西的时候,当我们点击付款,并付款成功的那一瞬间,程序就进行了多个操作,同时,把购买商品的信息入库,并同时产生商品快照,以及同时把客户买的商品的信息,推送给卖家,等等,这就大大的提高了用户的体验度,使得用户不用处于等待状态。
2、怎么实现多线程:
(1)继承Thread这个类,并重写run方法
(2)实现runnable这个接口,并实现run方法
(3)实现callable 这个接口,实现call方法,并用FutureTask来包装这个callable这个口,因为callable并没有继承runnable,而futureTask则实现了RunnableFuture而RunnableFuture这个接口则继承了runnable和future这个两个
3、三种实现的区别:
继承runnable和callable接口
优势:避免了单一的继承,可以实现多个接口,并且,callable会有返回值产生;
劣势:调用curreThread必须使用Thread来调用,当前的线程这个方法。
实现thread
优势:在方法里面可以直接用this就可以调用当前的对象
劣势:单一继承
三、线程的生命周期:
新建、就绪、运行、阻塞、死亡。
如下图所示:
怎么启动线程:
start()方法就会启动线程,但是启动线程以后,线程不会立即就进入运行状态,而是进入等待就绪状态。
怎么会出现阻塞:
(1)调用sleep处于系统会让出当前资源。
(2)调用IO阻塞方法,使得程序在返回之前一直处于阻塞状态。
(3)yied让出系统资源,使得当前的程序处于阻塞状态
(4)supend使线程挂起
(5)线程获取一个同步监测器,该同步监测器,该同步监测器,被其他线程占用,以至于获取该同步监测器,一直处于阻塞状态;
怎么唤醒阻塞线程:
(1)当sleep睡眠时间到了一个该线程自然就会被唤醒,但不会进入运行状态而是处于就绪状态,还要等待cpu;
(2)reseme()来使得挂起的程序再次处于就绪状态;
(3)试图获取同步监测器成功
(3)阻塞Io成功返回
(4)线程正在等待某个通知,然后其他线程发出了一个通知
线程死亡:
(1)线程执行完之后
(2)线程遇到未捕获exception或err就会出现线程死亡
四、线程中常用的一些方法:
(1)join:当两个线程并发执行的时候join方法可以等待当前线程执行完毕,另一个线程处于阻塞状态,当前线程执行完毕之后,才会执行。
(2) yeid:让出系统资源,使得正在运行的线程处于就绪状态(它不会使得程序处于阻塞状态),也有可能当线程刚刚处于就绪状态,就会运行了,取决于,该线程的优先级,是否比同处于阻塞下面其他线程优先级高
(3)sleep:这个方法会让线程处于阻塞状态,但是他不会释放锁,独占资源,只有sleep时间到之后才会释放资源。
(4)setPriority:设置线程的优先级 分别为:max_Priority 值 10、min_Priority 值 1、norm_priority 值 5
五、线程同步:
线程同步分为,同步方法和同步代码块synchronized
同步方法:
在方法体上面synchronized 进行同步操作,但是它不同的是整个对象(this),在性能方面同步方法相对同步块来讲,性能差
同步代码块:
在同步代码块的时候,如果多个线程并发去抢夺一个公有的资源。相对同步方法来讲性能较好
六、线程何时释放锁:
(1)释放锁:
1.当前线程遇到未捕获的异常或者遇到err()就会释放锁;
2.当前线程运行结束也会释放锁;
3.当前线程调用break,return也同样会释放锁
4.当前线程调用wait等待也同样会释放锁
(2)不释放锁
1.当前线程调用了sleep()、yeild()不会释放锁
2.其他线程调用suspend()挂起,会出现不会释放锁
七、死锁:
两个线程出现互相等待对方释放锁,就会产生死锁;
八、线层之间的通信:
wait():如果当前线程调用了该方法,则当前线程进入阻塞状态,但是会释放锁
notify:只能唤醒当前线程;
notifyAll:唤醒所有的线程
condition下面有:
await,signal,signalall与传统的线程通信是一样,但是condition功能更加的强大
典型案例:生产者与消费者
九、BlockingQueue控制线程通信
可模拟消费者与生产者:
当前队列已满,生产者在一次存入数据到队列中就会出现阻塞,如果当前队列已空,消费者取其中的数据也会出现阻塞,BlockingQueue继承了Queue接口
总结以下方法:
1、向队尾插入数据:
add(E e)、offer(E e)、put(E e)当队列已满,就会出现抛出异常、返回false、阻塞队列
2、在队列头部删除数据并返回删除的数据:
remove()、poll()、take()当队列已空,就会抛出异常、返回false、阻塞队列
3、队头取出数据但不删除数据:
element()、peek()当队列已空,就会抛出异常、返回false