后端八股之java并发编程

线程和进程

进程是一个正在运行的程序实例,一个进程下面有许多线程。不同的进程有不同的内存空间,同一进程下的所有线程共享进程的方法区资源,每个线程有自己的程序计数器,虚拟机栈和本地方法栈。线程更轻量,切换成本更低。

jdk1.2之前Java 线程是基于绿色线程(Green Threads)实现的,这是一种用户级线程(用户线程),之后Java 线程改为基于原生线程(Native Threads)实现,也就是说 JVM 直接使用操作系统原生的内核级线程(内核线程)来实现 Java 线程,由操作系统内核进行线程的调度和管理。

并行和并发

并行是指在同一时刻进行,并发是指在同一时间段进行

同步和异步

  • 同步:发出一个调用之后,在没有得到结果之前, 该调用就不可以返回,一直等待。
  • 异步:调用在发出之后,不用等待返回结果,该调用直接返回。

死锁

死锁就是双方互相持有对方需要的资源,并且不释放自己的资源,导致所有线程永久阻塞,无法继续进行

线程创建的方式

创建多线程的方式有继承Thread,重写callable,重写Runnable,线程池创建。

  • 生产环境首选:线程池(处理异步 / IO / 并发请求);

  • 需返回结果时:Callable+FutureTask(并发计算、拆分任务);

  • 简单解耦场景:Runnable(避免单继承);

  • 几乎不用:继承 Thread (单继承限制,无复用)。

    java 复制代码
    import java.util.concurrent.*;
    
    class MyThread1 extends Thread {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"->我正在以继承Thread的方式运行");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
    
    class MyThread2 implements Runnable {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"->我正在以重写Runnable的方式运行");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
    
    class MyThread3 implements Callable<Integer> {
        private int num;
        public MyThread3(int num) {
            this.num = num;
        }
        @Override
        public Integer call() throws Exception {
            System.out.println(Thread.currentThread().getName()+"->我正在以重写callable方式运行");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return num;
        }
    }
    /*
    Runnable 没有返回值,只能在内部消化异常不能往上抛 Callable有返回值,需要用futuretask获得返回结果,允许抛出异常。
     */
    
    class MyThread4 {
        static ExecutorService threadPool = Executors.newFixedThreadPool(5);
    
        public static void main(String[] args) {
            for(int i=1;i<=5;i++){
                threadPool.submit(()->{
                    System.out.println(Thread.currentThread().getName()+"->以线程池的方式进行");
                });
            }
        }
    }
    /*
    newFixedThreadPool(n):固定核心线程数,适用于任务量稳定的场景;
    newCachedThreadPool():弹性线程池,按需创建线程,空闲 60s 销毁;
    newSingleThreadExecutor():单线程池,任务串行执行;
    newScheduledThreadPool(n):定时 / 周期性任务线程池。
    */
    
    public class ThreadPractice {
        public static void main(String[] args) {
            MyThread1 thread11=new MyThread1();
            MyThread1 thread12=new MyThread1();
            thread11.setName("thread11");
            thread12.setName("thread12");
            thread11.start();
            thread12.start();
    
    
            MyThread2 myThread2=new MyThread2();
            Thread thread21=new Thread(myThread2,"thread21");
            Thread thread22=new Thread(myThread2,"thread22");
    
            thread21.start();
            thread22.start();
    
            MyThread3 myThread31=new MyThread3(1314);
            MyThread3 myThread32=new MyThread3(520);
    
            FutureTask<Integer> futureTask2=new FutureTask<Integer>(myThread31);
            FutureTask<Integer> futureTask1=new FutureTask<Integer>(myThread32);
    
            new Thread(futureTask2).start();
            new Thread(futureTask1).start();
    
        }
    }
  1. start() vs run()
    • start():触发 JVM 创建新线程,调用run(),只能调用 1 次(多次调用抛IllegalThreadStateException);
    • run():普通方法,直接调用不会创建新线程,主线程执行。
  2. 线程安全 :多个线程操作共享变量时会出现问题(比如计数错乱),后续可练习synchronizedLock解决;
  3. 线程状态:新建(New)→ 就绪(Runnable)→ 运行(Running)→ 阻塞(Blocked/Waiting/Timed Waiting)→ 终止(Terminated);
  4. 常用 API
    • Thread.sleep(long ms):让当前线程休眠(不释放锁);
    • Thread.yield():让出 CPU,线程回到就绪状态;
    • join():等待线程执行完成(比如thread1.join(),主线程等 thread1 执行完)。

线程的状态

Java 线程在运行的生命周期中的指定时刻只可能处于下面 6 种不同状态的其中一个状态:

  • NEW: 初始状态,线程被创建出来但没有被调用 start()
  • RUNNABLE: 运行状态,线程被调用了 start()等待运行的状态。
  • BLOCKED:阻塞状态,需要等待锁释放。
  • WAITING:等待状态,表示该线程需要等待其他线程做出一些特定动作(通知或中断)。
  • TIME_WAITING:超时等待状态,可以在指定的时间后自行返回而不是像 WAITING 那样一直等待。
  • TERMINATED:终止状态,表示该线程已经运行完毕。

乐观锁和悲观锁

乐观锁总是假设最好的情况,认为共享资源每次被访问的时候不会出现问题,线程可以不停地执行,无需加锁也无需等待,只是在提交修改的时候去验证对应的资源(也就是数据)是否被其它线程修改了(具体方法可以使用版本号机制或 CAS 算法)。

悲观锁总是假设最坏的情况,认为共享资源每次被访问的时候就会出现问题(比如共享数据被修改),所以每次在获取资源操作的时候都会上锁,这样其他线程想拿到这个资源就会阻塞直到锁被上一个持有者释放。也就是说,共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程

先发布吧 后面怎么写我再想想

相关推荐
茶本无香2 小时前
设计模式之二—原型模式:灵活的对象克隆机制
java·设计模式·原型模式
寻星探路2 小时前
【算法通关】双指针技巧深度解析:从基础到巅峰(Java 最优解)
java·开发语言·人工智能·python·算法·ai·指针
崇山峻岭之间2 小时前
Matlab学习记录32
开发语言·学习·matlab
向上的车轮2 小时前
如何选择Python IDE?
开发语言·ide·python
小北方城市网2 小时前
微服务接口设计实战指南:高可用、易维护的接口设计原则与规范
java·大数据·运维·python·微服务·fastapi·数据库架构
什么都不会的Tristan2 小时前
HttpClient
java·微信登录
隐退山林2 小时前
JavaEE:多线程初阶(二)
java·开发语言·jvm
乌暮2 小时前
JavaEE初阶---《JUC 并发编程完全指南:组件用法、原理剖析与面试应答》
java·开发语言·后端·学习·面试·java-ee
6***A6632 小时前
SpringSecurity+jwt实现权限认证功能
java