检测死锁的方式(java控制台) : jdk提供的方法 cmd输入jconsole 就可以查看状态
创建线程的4种方式:
1.继承Thread 类 重写run方法
-
实现Runnable接口
-
实现callable接口
调用 run()方法相当于 调用本地方法 没有开启线程
start()方法 开启线程 由jvm调用该线程的run()方法
线程执行的时机是由cpu安排调度决定的
线程的5大状态:
创建状态:new Thread() 创建线程对象
就绪状态:调用start()方法线程立即进入就绪状态,但不意味立即调度执行
阻塞状态:当调用sleep,wait或者同步锁定时,线程进入阻塞状态,就是代码不往下执行。阻塞时间接触后,重新进入就绪状态,等待cpu的调度执行。
运行状态:获得cpu调度 进入运行状态,线程才会真正执行执行线程体的代码
死亡状态:线程中断或者结束,一旦进入死亡状态,就不能再次启动
Thread.yield(); //线程礼让 那么所有的线都有处于就绪状态,同时争夺cpu的调用权
线程 6种状态:Thread.State 枚举类
getState()方法
new 创建状态// runnable 就绪状态(jvm虚拟机没有所谓的运行状态) // Blocked 阻塞状态 // waiting等待状态 terminated 死亡状态 time_waiting 等待另外一个线程的时间
线程调度模型:
分时调度模型: 所有的线程轮流使用CPU的使用权。平均分配每个线程占用cpu的时间片
抢占式调度模型:优先让优先级别搞得线程使用cpu,如果线程的优先级相同。name会随机选择一份。优先级高的线程获取cpu的时间相对多一些。
优先级: 默认优先级:5 最小 1 最大 10 优先级越大,只是抢到cpu的调度几率变大,不是一定的获得cpu调度就比低的多
setPriority()设置线程的优先级
getPriority() 获得线程优先级
守护线程:
setDaemon(true); 设置该线程为守护线程、表示:普通线程执行完毕之后。那么守护线程也没有继续执行的必要。就停止运行。
同步代码块
多个线程操作同一个共享数据时可以使用同步代码块实现
普通方法:synchronized(this){}
静态方法:静态方法多得锁对象(类名.class)对象
修饰符 static synchronized 返回值类型 方法名(方法参数 ){}
使用锁对象加锁;Lock
Lock lock =new ReentrantLock(); lock.lock()获得锁 lock.unlock()释放锁
释放锁一般在finally里面,防止死锁
锁 嵌套使用导致死锁
阻塞队列:
blockqueue: 阻塞队列 ArrayBlockquweue 基于数组结构实现类 LickedBlockQueue 基于链表结构
Object的wait(int timeOut)线程等待和 notify()和notifyAll()唤醒线程
wait的参数是超出等待时间线程会自动被唤醒进入就绪状态,不需要notify的唤醒
volatile
(修饰多线程共享数据 ,只能保证最新的数据,不能保证方法的原子性)
堆内存是唯一所有的线程共享一个的,一个线程对应一个线程栈
只能保证线程每一次使用共享变量都是查询堆内存最新的数据,但是不能保证线程的原子性(就是线程在运行方法时cpu切换调度别得线程)
解决办法:
1)同步代码块: Synchronized(){
}
同步代码块: 保证原子性(性能较低)
1.线程获得锁
-
清空变量副本
-
拷贝共享变量最新的值到变量副本中
-
执行代码
-
将修改后的变量副本中的值赋值给共享数据
-
释放
2)AtomicInteger() 保证数据的原子性(创建对象 参数就是共享数据 )
原子操作类()保证共享数据的原子性 可见性 基于cas算法
ABA解决方案; 添加版本号 就可以防止
5.如何获得线程安全的集合
HashTable()通过锁整个数组的机制 线程安全 但效率较低
ConCurrentHashMap() 效率较高
Collections.synchronizedConllection(new ArrayList())
在搜索框输入关键字的时候,异步将关键字保存在redis中 使用spring的线程池ThreadPoolTaskExecutor()对象
方法添加@Async(指定线程池对象的bean名称)
启动类类添加@EnableAsync