如何构建一个,涉及线程池与高并发技术?

摘要:多线程 Java创建线程的几种方式有哪些? 常见有以下五种方式创建使用多线程: 1)实现 Runnable 接口: 实现 Runnable&#16
多线程 Java创建线程的几种方式有哪些? 常见有以下五种方式创建使用多线程: 1)实现Runnable接口: 实现Runnable接口的run()方法,使用Thread类的构造函数传入Runnable对象,调用start()方法启动线程。 例子:Thread thread = new Thread(new MyRunnable()); thread.start(); 2)继承Thread类: 继承Thread类并重写run()方法,直接创建Thread子类对象并调用start()方法启动线程。 例子:MyThread thread = new MyThread(); thread.start(); 3)使用Callable和FutureTask: 实现Callable接口的call()方法,使用FutureTask包装Callable对象,再通过Thread启动。 例子:FutureTask<Integer> task = new FutureTask<>(new MyCallable()); Thread thread = new Thread(task); thread.start(); 4)使用线程池(ExecutorService): 通过ExecutorService提交Runnable或Callable任务,不直接创建和管理线程,适合管理大量并发任务。 例子:ExecutorService executor = Executors.newFixedThreadPool(10); executor.submit(new MyRunnable()); 5)CompletableFuture(本质也是线程池,默认 forkjoinpool): Java 8 引入的功能,非常方便地进行异步任务调用,且通过thenApply、thenAccept等方法可以轻松处理异步任务之间的依赖关系。 CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {}); 线程生命周期及五种状态 1、New(初始化状态) 用new语句创建的线程处于新建状态,此时它和其他Java对象一样,仅仅在堆区中被分配了内存。如:Thread t = new MyThread(); 2、Runnable(就绪状态) 当调用线程对象的start()方法,线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,Java虚拟机会为它创建方法调用栈和程序计数器。处于这个状态的线程位于可运行池中,等待获得CPU的使用权,并不是说执行了start()此线程立即就会执行。 3、Running(运行状态) 当就绪状态中的线程获得了CUP执行资源,执行run()中的代码,这样的线程我们称为运行状态的线程。 4、Blocked(阻塞状态) 处于运行中的线程,由于某种原因放弃对cpu的使用权,处于阻塞状态,直到其进入就绪状态,才有机会再次被cpu调用进入运行状态。 根据阻塞原因不同,阻塞分为三种: 等待阻塞:运行状态中的线程执行wait方法,进入等待队列,等待阻塞;Java虚拟机就会把线程放到这个对象的等待池中; 同步阻塞:线程获取同步锁失败(因为锁被其他线程占用),Java虚拟机就会把这个线程放到这个对象的锁池中; 其他阻塞:通过调用sleep方法或者join方法或者发出I/O请求时,线程会进入阻塞状态,当sleep()状态超时,或者join()等待线程终止或者超时,或者I/O处理完毕,线程重新转入就绪状态; 5、Terminated(终止状态) 正常结束,线程执行完 异常退出 异常退出,除了程序有问题导致的异常的退出,还可以使用共享变量的方式(定义个boolean标识等)退出,或者Interrupt中断线程,抛出异常,捕获异常break,跳出循环状态; 调用stop(),会造成死锁,线程不安全,不建议使用 线程基本方法 1、线程等待(wait) 调用该方法,线程进入waiting状态,只有等待另外的线程通知或被中断才会返回,调用wait()后,会释放对象锁,因为wait方法一般用在同步方法或者同步代码块中。 2、线程睡眠(sleep) 强迫一线程睡 N毫秒,sleep不会释放当前锁,导致线程进入Timed-wating状态。 3、线程让步(yield) yeild会使当前线程让出cpu执行时间片,与其他线程一起重新竞争cpu时间片,一般情况下,优先级高的先得到,但也不一定,有的系统对优先级不敏感。
阅读全文