自我总结高并发基础
程序员文章站
2022-06-30 20:48:32
...
java高并发
maven生命周期
1. clean 生命周期:clean 生命周期的目的是清理项目
2. default 生命周期:default 生命周期定义了构建项目时所需要的执行步骤,它是所有生命周期中最核心部分
3. site 生命周期:生命周期的目的是建立和发布项目站点。
servlet生命周期
1.加载和实例化
2.初始化
3.请求处理
4.服务终止
bean生命周期
1.Bean的定义
2.Bean的初始化
3.Bean的使用
4.Bean的摧毁
线程生命周期
1.新建
2.就绪
3.运行
4.阻塞
5.销毁
JAVA多线程
进程: 一个正在执行的程序就是进程
例如:任务管理器中跑起来的任务,QQ的启动,微信的启动等
线程: 一个进程可以有多个线程,具体执行任务的最小单位
进程和线程的联系:
1:一个进程可以拥有多个主线程
2:线程之间可以共享资源(每个内存资源都是由进程申请的)
3:线程之间可以通信,(进行数据传递:多数为主线程和子线程)
Java中Runnable和Thread的区别:
在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口;Thread类是在java.lang包中定义的。一个类只要继承了Thread类同时覆写了本类中的run()方法就可以实现多线程操作了,但是一个类只能继承一个父类,这是此方法的局限。
实现线程的几种方式:
1.继承Thread类,重写run方法
2.实现Runnable接口,重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函数的target
public static void main(String[] args) {
new Thread(new Task()).start(); //新建一个线程,并且启动
System.out.println(1);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(2);
System.out.println(4);
}
static class Task implements Runnable{
@Override
public void run() {
System.out.println(3);
}
}
3.通过Callable和FutureTask创建线程
public static void main(String[] args) {
System.out.println(3);
FutureTask<Integer> integerFutureTask = new FutureTask<Integer>(new Task()); //将Task 类的返回值赋给integerFutureTask
new Thread(integerFutureTask).start(); //阻塞作用,当integerFutureTask调用完成之后在进行下一步
System.out.println(4);
try {
Integer integer = integerFutureTask.get();
System.out.println(5);
System.out.println(integer);
System.out.println(6);
} catch (Exception e) {
e.printStackTrace();
}
}
static class Task implements Callable<Integer>{
@Override
public Integer call() throws Exception {
Thread.sleep(1000);
return 1;
}
}
4.通过线程池创建线程
守护线程:
Java提供两种类型的线程: 用户线程 和 守护程序线程 。
去守护另一个线程,当被守护线程宕机,那么守护者线程也会宕机,例如启动QQ聊天窗口,当关闭QQ时候,这个qq窗口也会关闭.请求窗口就相当于守护者.
创建守护者
NewThread daemonThread = new Thread();
daemonThread.setDaemon(true);
daemonThread.start();
多线程问题解决:
synchronized:jdk内置的锁 内置锁
解决线程安全的两种方法:
1.synchronized(监听器/对象/对象的一把锁)
{
//需要同步的代码
}
代码:
public class Ticket implements Runnable {
private static final Object monitor = new Object(); //创建一个监视器,如果多个线程进来,就需要一个监视器
public static int count = 100; //定义总的票数
String name;
public Ticket(String name) {
this.name = name;
}
@Override
public void run() {
while (count > 0) {
ThreadUtils.ThreadUtil(100);
//synchronized将对象建立一个锁
synchronized (Ticket.monitor) {
System.out.println(name + "出票一张,还剩" +count-- + "张!");
}
}
}
public static void main(String[] args) throws Exception {
Thread one = new Thread(new Ticket("一号窗口"));
Thread two = new Thread(new Ticket("二号窗口"));
one.start();
two.start();
Thread.sleep(10000);
}
}
2.ReentrantLock
定义一个lock锁
private static ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (count > 0) {
ThreadUtils.ThreadUtil(100);
lock.lock();//上锁
System.out.println(name + "出票一张,还剩" + count-- + "张!");
lock.unlock();//解锁
}
}
synchronized锁升级
偏向锁:锁偏向于某个进程,偏向锁的作用是当有线程访问同步代码或方法时,线程只需要判断对象头的Mark Word中判断一下是否
有偏向锁指向线程ID.仅有一个线程进入临界区
例子:假如家里只有一个碗,当我自己在家时,没有人会和我争碗,这时即为偏向锁状态
什么时候升级成轻量级锁?
其他线程竞争资源时,偏向锁就会被撤销。
轻量级锁:
多个线程交替进入临界区
例子:当我和女朋友都在家吃饭时,如果女朋友不是很饿,则她会等我吃完再用我的碗去吃饭,这就是轻量级锁状态
自旋锁:
A进入餐厅,B守在门口,C过来和B握手,十次之内,A还没有出来,C就去排队等待.
重量级锁:
多个线程同时进入临界区
例子:当自旋锁不成功时候,就会进入阻塞队列,进行排队,之后进入的线程也必须排队才行
Lock
lock.tryLock() 获取锁
方式一:
Lock lock = ...;
if (lock.tryLock()) {
while (count > 0) {
try {
lock.lock();
方法体……
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();//释放锁
}
}
}else {
}
}
方式二:
Lock lock = ...;
lock.lock();
try{
//处理任务
}catch(Exception ex){
}finally{
lock.unlock(); //释放锁
}
ReadWriteLock读写锁
1
可重入锁:
*当我获取到C锁的同时也可以获取到C锁中的其他锁
public static final Object lock = new Object(); //new一个对象
public static synchronized void A(){
System.out.println("A锁");
}
public static void B(){
synchronized (lock){
System.out.println("B锁");
}
}
public static synchronized void C(){
A();
B();
}
public static void main(String[] args) {
C();
}
各种锁:
读写锁:
乐观锁(自旋锁):
悲观锁(排队):
公平锁(所有线程进入都必须排队):
非公平锁(可以插队):