多线程
1、使用继承Thread类,还是实现Runable接口好?
当然是实现Runable接口好
原因实现了接口还可以继类,继承了类就不能继承或者实现了
2、Thread.sleep(1000);
1000指的是毫秒数,也就是1秒
sleep方法的作用是:让当前线程从运行状态变为休眠状态,时间到期自动变为运行状态
注意:sleep不能释放锁,多线程吧之前实现同步,wait()可以释放锁
3、多线程的运行状态
(1)、新建状态
new **Thread() 新建一个线程
(2)就绪状态
线程调用start()方法,就绪
(3)运行状态
线程在执行run()方法的逻辑
(4)死亡状态
run()方法走完了,线程就会被停止,或者调用stop()方法
(5)、阻塞状态
调用sleep()方法,时间结束会变为就绪状态
4、多线程使用案例
案例:10万用户,发送短信
为了提高程序的效率,使用多线程分批发送
每多开一个线程,都会占用cpu资源
开启线程的多少,与服务器(电脑)的配置,cpu,核数有关
5、join()方法
join()方法的作用是让其他线程变成等待状态
例如:t1.join()—>就是让其他线程变成等待,直到当前t1线程执行完毕,才释放,然后其他线程继续执行
面试题:有T1、T2、T3三个线程,怎么保证T2在T1之后执行,T3在T2之后执行?
在T2的线程中(也就是run方法中调用t1.join()方法),在T3的线程中(也就是run方法中调用t2.join()方法)
这样就变成了单线程,但是在实际情况中会有线程等待的问题,实际上还是多线程。
多线程之间实现同步
1、什么是线程安全问题?
答:在多个线程共享同一个全局变量,在做写操作的时候,可能会收到其他线程的干扰,导致数据有问题,这种现象就是线程安全问题。
2、案例
现在有100张火车票,有两个窗口同时抢火车票,请使用多线程模拟抢票效果。
使用线程同步。但是如何实现同步,如何保证数据的原子性?
(1)使用同步代码块
sychronized(Obj){
//TODO 具体代码逻辑
}
(2)使用同步函数-->在方法上加sychronized
public sychronized void sale(){
//TODO 具体代码逻辑
}
3、同步函数使用的是this锁
面试题:一个线程使用同步函数,一个线程使用同步代码块,并使用this锁,能保证同步嘛?答:可以
4、静态同步函数
首先静态同步函数使用的不是this锁
注意:当一个变量被static关键字修饰的时候,就会被存放在永久区,当class文件被加载的时候就会被初始化
所以:静态同步函数使用的锁是:类的字节码文件,也就是类名.class
加锁是保证同步,同步时保证数据的安全问题和原子问题。
分布式锁、高并发和JVM没有关系。
使用sychronized和lock,都属于单个JVM同步
多线程死锁
讲多线程死锁问题之前,先了解一下什么是java内存模型
1、java内存模型–>多线程可见性JMM
java内存模型一定要与java内存结构区分开。java内存结构指的是JVM内存分配相关
概念:共享内存模型指的就是java内存模型(简称:JMM)
JMM决定一个线程对共享变量的写入时,能对另一个线程可见
java内存模型:主内存:(主要存放共享的全局变量) 私有本地内存:(本地内存私有变量) 注意:本地内存存放的是从主内存中复制的共享数据的副本
2、多线程的三大特性
①、原子性:保证线程的安全问题
②、可见性:java内存模型
③、有序性:join,wait,notify
3、同步中嵌套同步,互不释放锁
例如:线程1,先拿到同步代码块的obj锁,然后再拿到同步函数的this锁;线程2呢,先拿到同步函数的this锁,再拿到同步代码块的obj锁,然后这两个线程都在等待对方释放锁,这样就造成了死锁。
volatile(可见性)
关键字:作用是变量在多个线程之间可见
保证线程的可见性,但不保证原子性
//需要10个线程同时共享count,static关键字,存放在静态区,但只会存放一次,所有的线程都共享
private volatile static int count = 0;
AtomicInteger(原子类)
保证数据的原子性
面试题:JDK1.5的并发包有哪些?
Atomic