进程线程多线程

    我知道的是我一无所知

谢谢拉钩教育张雷老师《32个java面试必考点》王磊老师《java源码剖析34讲》还有各大佬们的分享,

进程与线程

进程与线程,这个真的是老生常谈到你不知道他是多么的重要,由点及面可以说到天荒地老,不要紧张,有时候天荒地老 眨眼就到

    进程系统资源分配的最小单位,拥有独立的数据空间

    线程:程序执行的最小单位,共享进程的数据空间,当然作为独立的thing也有自己的空间

进程

  程序动态运行的实例,操作系统使用task_struct结构体标识进程

task_struct 

  • 标识符:唯一标识
  • 状态:R(running)运行,S(sleeping)可中断的休眠,D(disk sleep)不可中断的休眠,需“唤醒”,T(stopped)停止,t(tracing stop)追踪,X(dead)死亡,Z(zombie)僵死
  • 上下文数据:进程执行时处理器的寄存器中的数据
  • 程序计数器:进程下一次要执行指令的地址
  • 优先级:进程被执行的先后顺序问题
  • IO状态信息:显示的I/O请求,分配给进行的I/O设备和被进程使用的文件列表等
  • 记账信息:有处理器的时间总和、记账号等

详情请咨询:https://blog.csdn.net/bit_clearoff/article/details/54292300 

 

指令

我们常见的亲切的top大哥

ps -ef | pid 查询all进程信息

ps aux:查看进程详细信息

当然还有很多,k8s、docker也有索性使用起来大同小异

线上问题排查pid也是起了很大的作用,这块完全可以另起一篇了

优先级

ps -l或者top命令

优先级PRI:可被执行的优先级、值越小优先级越高

真实进程的PRI=PRI+nice,nice可修改

    未运行的进程 nice -n setValue 程序,如 nice -n -10 ./test

    已经运行的进程renice setValue -p pid,如 renice  -10  -p  4500

地址空间

进程地址空间是虚拟地址,虚拟地址和物理地址页表关联

写时复制

   父子进程修改全局变量时,物理内存空间将重新分配内存保存父子进程修改后的值并刷新页表,所以虚拟内存地址不变值不一定相同

摘自:https://blog.csdn.net/ksaila/article/details/83794568 

 

进程间通信 :

     1、管道pipe:管道是半双工通信,数据在有亲缘关系(父子)进程间单向流动

     2、命名管道FIFO:半双工通信,无亲缘关系也可以通信

     3、消息队列messageQueue:双向通信,全局链表,节点保存数据报的类型和内容,消息队列标识符标记

     4、共享存储sharedMemory:由一个进程创建,将同一物理内存映射到不同进程虚拟地址空间中,这样就不需要用户态与内核态的来回切换还有数据拷贝(是不是很ok),直接被多个进程访问的内存也是危险,你争我抢、完整的人进去 四分五裂的出来,还是要保证原子性,如何实现?信号量、互斥锁,牛奶咖啡冰淇淋了解一下

    5、信号量semaphore:无论如何花里胡哨,说计数器多好,东西就这么少、你想要问一下信号量有没有资格!是的,控制多个进程对共享资源的访问和同一进程不同线程同步的利器,数组元素+1 -1 了解一下

    6、套接字socket:不同机器间的进程通信,机器哦不是进程

    7、信号sinal:进程间、同一进程不同线程间同步手段

 

线程

    像一条条赛道,什么都没有来回瞎跑,马路还有个地标呐!线程用状态标记一下吧

创建线程

1、继承Thread并重写run方法,创建子类对象并调用start,这个讲解的时候用到挺多的

public class Thread1 {
     
    public static void main(String[] args) {
        //创建一个新线程
        ThreadDemo1 thread1 = new ThreadDemo1();
        //为线程设置名称
        thread1.setName("线程一");
        //开启线程
        thread1.start();
    }
}
 
public class ThreadDemo1 extends Thread{
     
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
     
}

2、实现Runnable接口的类实现run方法,类对象在创建Thread时作为参数传入,调用start方法

public class Thread2 {
     
    public static void main(String[] args) {
        Thread.currentThread().setName("主线程");
        System.out.println(Thread.currentThread().getName()+":"+"输出的结果");
        //创建一个新线程,注意参数
        Thread thread2 = new Thread(new ThreadDemo2());
        //为线程设置名称
        thread2.setName("线程二");
        //开启线程
        thread2.start();
    }
     
}
 
public class ThreadDemo2 implements Runnable {
 
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+":"+"输出的结果");
    }
     
}

3、实现callable接口,重写有返回值可抛异常的call方法

public class Thread3 {
     
    public static void main(String[] args) throws Exception {
        //创建FutureTask的对象,参数
        FutureTask<String> task = new FutureTask<String>(new ThreadDemo3());
        //创建Thread类的对象,参数
        Thread thread3 = new Thread(task);
        thread3.setName("线程三");
        //开启线程
        thread3.start();
        //获取call()方法的返回值,即线程运行结束后的返回值
        String result = task.get();
        System.out.println(result);
         
    }
     
}
 
class ThreadDemo3 implements Callable<String> {
 
    @Override
    public String call() throws Exception {
        System.out.println(Thread.currentThread().getName()+":"+"输出的结果");
        return Thread.currentThread().getName()+":"+"返回的结果";
    }
}

start与run

start启动新线程,状态为runnable、要为线程分配系统资源、调度线程运行并执行run方法

run实际要做的工作,runnable到running

先说一下java变量吧?这篇博客眼看着越来越庞大,这样是不是不好

       类变量、静态变量:独立于方法之外的,嗯?什么是方法之外,我想送你离开,用static修饰这样是不是好懂一些,关于static也可以开篇来一个,累了不写了

       实例变量、成员变量:独立方法之前外,诶?这个不和上面的一样吗?不急 我还没有写完,自然没有static修饰,否则岂不是要怀疑人生

       局部变量:声明在方法、构造方法、语句块中,栈上分配

 

每个对象都有一把锁,锁定类实例或类对象

加锁:synchronized

1、方法上,同步方法,锁定类实例

      同一对象只有一把锁,不同的对象是互不影响的

2、类变量、类方法上,static

     锁定类对象,属于类的,在jvm中独一份,访问这个类相关的方法前都要先问这个锁闲不闲

     如果类中使用了synchronized定义非静态方法,影响all使用这个方法的方法

     如synchronized定义静态方法,影响类中all使用该方法的方法

3、同步代码块

锁释放:jvm把该线程对应的本地内存中共享变量刷新到主内存

获取锁:jvm将线程对应的本地内存置为无效,被锁保护的临界区代码从主内存读取变量

 

用前先想一下;当前是类还是对象,锁在哪

lock:略

 

状态

说这块那铁定少不了那张编程界流传已久的——图

线ç¨ç¶æå¾

简要解释一下、图其实很明晰了:

   就绪状态:可运行,等待获取CPU使用权

         调用start进入

          线程sleep结束,其他线程join结束,线程拿到对象锁 进入

          当前线程时间片用完,调用当前线程yield,当前线程进入

    阻塞状态:某种原因放弃cpu使用权,暂停运行找到进入就绪态

           等待阻塞:wait,等待队列

           同步阻塞:想要得到的同步锁被别的线程占用,jvm将线程放入锁池

            其他阻塞:运行线程执行sleep或join 或 I/O请求 ,jvm把线程置为阻塞 

这张图也是很形象了,源于图上的连接,博客的访问量、好评都挺高的;同步、等待队列这张图说的很明白了

    同步队列:想要争夺锁的线程,线程唤醒之后进入的是同步队列去争夺锁

          如获得锁进入runnable状态,否则blocked状态

 

https://blog.csdn.net/pange1991/article/details/53860651?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase

 

è¿éåå¾çæè¿°

https://blog.csdn.net/qq_27717921/article/details/77418128

那就多看几遍,刻意练习

 

也找到一张图,谢谢作者大大 同时也谢谢这么努力的自己个儿

源自: https://www.cnblogs.com/thinfog/p/11250913.html 谢谢

 

线程调度:下面的这些台词多少在zk、nginx、kafka上也都是排面,所以学会了是不是有些以一敌百的小确幸

     时间片轮询、先来先服务、优先级调度、多级反馈队列及高响应比优先调度

方法解释

  • sleep当前线程调用,让出CPU时间片、不释放锁,给其他线程执行机会
  • yield当下线程调用,放弃cpu时间片不释放锁,运行态变就绪态,优先级高的执行机会大
  • join/join(long millis)当前线程调用其他线程的join(),当前线程进入waiting/timed_waiting态,不释放锁,线程执行完或时间到了当前线程一般会进入runnable,也可能blocked(join就wait实现)
  • obj.wait当前线程调用对象的wait方法,必须在synchronized中,当前线程释放锁进入等待队列,靠notify或notifyAll唤醒或wait(long timeout) 等timeout后自动唤醒
  • locksupport.park / lockSupport.parkNanos(long nanos) / lockSupport.parkUntil(long deadlines)当前线程进入waiting / timed_waiting,通过lockSupport.unpark(Thread thread)唤醒
  • notify、notifyAll必须在synchronized中
https://blog.csdn.net/ywlmsm1224811/article/details/94022647 

static class MyThread1 implements Runnable {
 
        @Override
        public void run() {
            synchronized (obj) {
                System.out.println("thread1 start");
                try {
                    obj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("thread1 end");
            }
        }
    }

static class MyThread2 implements Runnable {
 
        @Override
        public void run() {
            synchronized (obj) {
                System.out.println("thread2 start");
                obj.notify();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("thread2 end");
            }
        }
    }
static class MyThread1 implements Runnable {
 
        @Override
        public void run() {
            synchronized (obj) {
                System.out.println("thread1 start");
                   Thread.yield();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("thread1 end");
            }
        }
    }

wait让出CPU时间片释放锁

yield涉及到优先级

   线程创建时,子继承父的优先级

   线程创建后,可通过setPriority改变,优先级是0-10间整数,正比

 

 

线程池

fixedThreadPool和singleThreadPool:容许请求队列长度为Integer.MAX_VALUE,可能会堆积大量请求,导致OOM

cachedThreadPool和scheduledThreadPool:容许创建线程数量为integer.MAX_VALUE,可能会创建大量线程、导致OOM

//corePoolSize线程池常驻核心线程数,设置为0无任务时销毁线程池,>0无任务时池中线程数==该值,据业务调整
//线程池最大可创建的线程数,必须>0,>corePoolSize
//线程存活时间,线程池空闲且超过该时间 多余线程会销毁
//存活时间的单位,配合keepAliveTime使用
//线程池执行的任务队列,池中线程都在处理任务新来的任务进入该队列等等执行
//线程的创建工厂,使用时可以不指定使用默认工厂
//拒绝策略,缓存任务队列满且不能创建新线程,使用何种策略拒绝
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
        // maximumPoolSize 必须大于 0,且必须大于 corePoolSize
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.acc = System.getSecurityManager() == null ?
            null :
            AccessController.getContext();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

threadPoolExecutor扩展

 重写beforeExceute和afterExecute 

public class ThreadPoolExtend {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 线程池扩展调用
        MyThreadPoolExecutor executor = new MyThreadPoolExecutor(2, 4, 10,
                TimeUnit.SECONDS, new LinkedBlockingQueue());
        for (int i = 0; i < 3; i++) {
            executor.execute(() -> {
                Thread.currentThread().getName();
            });
        }
    }
   /**
     * 线程池扩展
     */
    static class MyThreadPoolExecutor extends ThreadPoolExecutor {
        // 保存线程执行开始时间
        private final ThreadLocal<Long> localTime = new ThreadLocal<>();
        public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
                            TimeUnit unit, BlockingQueue<Runnable> workQueue) {
    super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
        /**
         * 开始执行之前
         * @param t 线程
         * @param r 任务
         */
        @Override
        protected void beforeExecute(Thread t, Runnable r) {
            Long sTime = System.nanoTime(); // 开始时间 (单位:纳秒)
            localTime.set(sTime);
            System.out.println(String.format("%s | before | time=%s",
                    t.getName(), sTime));
            super.beforeExecute(t, r);
        }
        /**
         * 执行完成之后
         * @param r 任务
         * @param t 抛出的异常
         */
        @Override
        protected void afterExecute(Runnable r, Throwable t) {
            Long eTime = System.nanoTime(); // 结束时间 (单位:纳秒)
            Long totalTime = eTime - localTime.get(); // 执行总时间
            System.out.println(String.format("%s | after | time=%s | 耗时:%s 毫秒",
                    Thread.currentThread().getName(), eTime, (totalTime / 1000000.0)));
            super.afterExecute(r, t);
        }
    }
}

线程池的工作流程:

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
    // 当前工作的线程数小于核心线程数
    if (workerCountOf(c) < corePoolSize) {
        // 创建新的线程执行此任务
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    // 检查线程池是否处于运行状态,如果是则把任务添加到队列
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        // 再出检查线程池是否处于运行状态,防止在第一次校验通过后线程池关闭
        // 如果是非运行状态,则将刚加入队列的任务移除
        if (! isRunning(recheck) && remove(command))
            reject(command);
        // 如果线程池的线程数为 0 时(当 corePoolSize 设置为 0 时会发生)
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false); // 新建线程执行任务
    }
    // 核心线程都在忙且队列都已爆满,尝试新启动一个线程执行失败
    else if (!addWorker(command, false)) 
        // 执行拒绝策略
        reject(command);
}

addWorker(Runnable firstTask,boolean core)

      firstTask线程应首先执行的任务,没有则设null

      core是否可创建线程的阈值,true将corePoolSize作为最大值,false使用maximumPoolSize作为最大值

submit与execute均执行线程池任务

   submit属于ExecutorService接口方法,可接收线程池执行的返回值Future<> 

   execute属于Executor接口方法,无返回值

拒绝策略

     abortPolivy终止策略,线程池抛异常并终止执行,默认的

      callerRunsPolicy任务交给当前线程执行

      discardPolicy忽略此任务(最新的任务)

      discardOldestPolicy忽略最早的任务(最先加入队列的任务)

自定义拒绝策略

  新建 RejectedExecutionHandler 对象,然后重写它的 rejectedExecution() 实现自己的逻辑

 

携程、抱歉,是协程:比线程更轻量级的存在,特殊函数、协程间串行执行

     在用户态调整,切换由程序决定进行硬件上下文的切换,更加轻量化、切换代价自然比线程上下文切换低很多

     进程切换时机操作系统的策略,含全局目录、内核栈、硬件上下文、切换内容存内存中,so用户态到内核态到用户态

     线程切换由操作系统决定,含内核栈和硬件上下文,切换内容保存在内核栈中

谢谢亲们,今天呐咱们就到这,散了吧

https://www.jianshu.com/p/6dde7f92951e

https://www.cnblogs.com/li666/p/11139968.html

https://www.runoob.com/java/java-variable-types.html

https://blog.csdn.net/u013262534/article/details/81676657

https://blog.csdn.net/zhaohong_bo/article/details/89552188

https://blog.csdn.net/qq_27717921/article/details/77418128

https://blog.csdn.net/zjy15203167987/article/details/82531772

https://kaiwu.lagou.com/course/courseInfo.htm?courseId=1#/detail/pc?id=3

https://blog.csdn.net/gatieme/article/details/50908749?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase

https://blog.csdn.net/wm12345645/article/details/82381407?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase

https://blog.csdn.net/qq_41333582/article/details/83988370?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase

https://blog.csdn.net/csdnnews/article/details/82321777?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4.nonecase

https://blog.csdn.net/pange1991/article/details/53860651?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值