java回顾之多线程
一、多线程
1、并行与并发
并行:多个事件都在执行,并在某个时刻多个事件是同时执行
并发:多个事件都在执行,但是在某个时刻多个事件没有同时执行。
2、进程与线程
进程:一个进程就是应用程序的一次执行
线程:线程是进程的执行单元。一个进程中可以包含多个线程,一个进程起码有一个线程。
3、Thread类
构造方法:
Thread() 创建线程对象 Thread(String name) 创建线程对象并指定线程名字
Thread(Runnable target) 使用Runnable创建线程
Thread(Runnable target,String name) 使用Runable创建线程并指定线程名字
常用方法:
getName() 获取线程的名字
start() 开启线程,每个对象只调用一次start
run() run方法写线程执行的代码
sleep() 让当前线程睡指定的时间
currentThread() 获取当前线程对象
4、创建线程的方法
4.1、继承方式
写一个类,继承Thread类,重写run方法,用start开启线程
4.2、实现方式
创建一个类,实现Runnable接口,重写run方法,run方法写线程执行的代码,然后创建对象,将实现接口的对象作为参数,传入Thread对象中
这种方式太麻烦,还可以用匿名内部类的方式,直接将代码写出来
一个是匿名内部类继承Thread类,一个是匿名内部类实现Runable接口
在普通情况下你想用哪种就用哪种。
java中类是单继承的,如果一个类已经有一个父类了,那么只能实现一个接口而不能再去继承一个类。
匿名内部类的方式完全是为了简化代码,你想用就用不想用就不用。、
4.3 callable开启多线程
callable有两个好处,可以写返回值类型,可以抛出异常。
5.安全性问题
线程在高并发的情况下,有安全性问题
1、可见性:一个线程将某个变量的值修改了,但是主线程跑的快,当主线程读取到这个变量的值时,值还没有修改,主线程就会默认这个变量的值不会变量,所以当子线程将值修改后,主线程也没有读取到改变的值
解决这个问题可以使用volatile关键字修饰成员变量,可以解决可见性问题
public static volatile int a = 0;
5.2有序性问题
代码编译期间,代码没有上下的逻辑关系,系统可能出现代码重排的现象,就是会先执行后面的代码再执行前面的代码
这个解决办法也是用volitile关键字
5.3原子性问题
当多个线程修改同一个变量的时候,比如线程一对变量a进行自增,当a=1000的时候,线程一正在修改还没有返回,线程二将a=1000读取走了,这时候线程一将a=1001返回,然后线程二也将a=1001返回,a等于了两回1001
解决原子性问题,第一个方法可以使用原子类来解决
AtomicInteger:对int变量操作的原子类
AtomicLong:对long变量操作的原子类
AtomicBoolean:对boolean变量操作的“原子类”;、
AtomicInteger工作机制-CAS机制
AtomicIntegerArray:原子类数组,解决数组的原子性问题
多线程的内存机制