1. 什么是进程,什么是多线程?
进程是系统进行资源分配和调度的一个独立单位,所有运行中的任务通常对应一个进程。
当程序运行时,内部可能包含多个顺序执行流,每个顺序执行流就是一个线程,多线程是实现多个线程并发执行的技术。
(并发:通俗讲是同一时刻只做一件事;并行:同一时刻做多件事)
2.多线程的实现方法有三种 :
一:实现runnable接口(实现接口里的run方法)特点:可以实现多个接口,比较灵活;但是不能直接启动,经常使用;
二:继承Thread类(直接复写父类run方法)特点:直接启动,方法较多;但是只能继承一个类,不能多继承,不常使用;
三:实现callable接口(实现里面的call方法)特点:有返回值,可以抛出异常,比较好控制;只有jdk1.5以上才支持,需要返回值的时候使用
3.线程状态有5种:
new:新建一个线程对象
runnable:就绪状态,当线程对象创建后,其他线程(如main)调用了该对象的start()方法,该线程就进入了可运行线程池中,等待被线程调度选中,获取cpu的使用权。
running:运行状态,可运行状态的线程获得了cup的使用权后,执行程序代码。
blocked:阻塞状态,线程因为某种原因放弃CPU使用权,暂时停止运行,直到线程进入就绪状态,才有机会转到运行状态。
三种阻塞情况:
等待阻塞(调用wait方法)
同步阻塞(等待同步锁中其他线程释放锁)
其他阻塞(调用sleep或join方法)
Dead(带特):死亡状态,线程run(),main()方法执行结束,或异常退出run()方法
常见的属性:
守护线程:通过setDaemon方法设置,守护线程伴随主线程的结束而结束,守护线程创建的线程也是守护线程
线程优先级:最高10,最低1,默认5
线程中断:不能用stop暴力停止,对机器损耗大,一般用interrupt()方法
4.线程常见方法:
start:启动一个线程时调用,但线程不会立即运行,要等获取CPU的使用权后才执行。
sleep:让程序暂停,休眠指定的时间。
run:子类重写来实现线程的功能,程序会将它看做一个普通方法来执行。
yield:暂停当前执行的线程,让给其他线程。
join:等待当前线程终止
setDaemon:设定当前线程为守护线程
setName:设定当前线程的名字
interrupt:用来中断当前线程
currentThread:主要在Runnable接口的实现里面用,得到当前的Thread
setPriority:设定线程的优先级
5.线程安全问题
定义:当多个线程同时访问对象的时候不会发生数据混乱就叫线程安全。
解决线程不安全:
不同线程之间不共享变量(不使用字段变量,多用局部变量;使用ThreadLocal
尽量用final修饰(将共享变量修改为不可变的变量)
使用同步方法,同步块或lock锁(在用共享变量时用同步)
6.线程通信
1.同步块或者同步方法
同步方法就是被synchronized修饰的方法,同步整个方法,整个方法都会被锁住,
同一时间只有一个线程可以访问该方法。缺点:性能差
同步块就是使用synchronized修饰的代码块,可以同步一小部分代码,性能比较高
2.线程死锁;
死锁就是当有两个或两个以上的线程都获得对方的资源,但彼此有不肯放开,处于 僵持状态,此时便造成了死锁。
解决方案:
synchronized尽量不用嵌套;线程按照同样的顺序获得一把锁, 不要在递归函数中使用锁,在检查某个资源时,可以用超时机制。
3.阻塞队列
当put增加元素到队列,如果队列满了,则阻塞线程
当take取出元素,如果队列为空,则阻塞线程
4.Lock锁中的同步
5.生产者与消费者
生产者:生产数据
消费者:处理数据
缓冲区:生产者与消费者的缓冲区
线程缺点:耗费资源,有线程安全问题,线程越多越不好控制。
7.多线程相关的类
集合类:
原子类:(用来解决读取线程不安全问题)
线程池类:
线程池就是用来存储线程的,是线程的集合
简化线程的创建,销毁以及日常管理
8、为什么要使用线程池
使用线程可以很好的避免线程创建销毁导致的性能开销,尤其是程序中需要创建大量的生存期很短的线程时,更应该考虑使用线程池,线程池中的每条线程执行完任务后并不会进入死亡状态,而是回到线程池中变成空闲就绪状态,等待下一次使用,能够自动管理线程的生命周期。