JAVA 多线程编程
一、线程和进程
进程:是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。
线程:是进程的一个执行路径,一个进程中至少有一个线程,进程中的多个线程共享进程的 资源。
虽然系统是把资源分给进程,但是CPU很特殊,是被分配到线程的,所以线程是CPU分配的基本单位。
二者联系
一个进程中有多个线程,多个线程共享进程的堆和方法区资源,但是每个线程有自己的程序计数器和栈区域。
程序计数器:是一块内存区域,用来记录线程当前要执行的指令地址 。
栈:用于存储该线程的局部变量,这些局部变量是该线程私有的,除此之外还用来存放线程的调用栈祯。
堆:是一个进程中最大的一块内存,堆是被进程中的所有线程共享的。
方法区:则用来存放 NM 加载的类、常量及静态变量等信息,也是线程共享的 。
二者区别
进程:有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响。
线程:是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉。
- 简而言之,一个程序至少有一个进程,一个进程至少有一个线程。
- 线程的划分尺度小于进程,使得多线程程序的并发性高。
- 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
- 每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
- 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别
二、创建线程的四种方式
1. 继承 Thread 类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class ThreadDemo extends java.lang.Thread {
@Override public void run() { for (int i = 1; i <= 5; i++) { System.out.println(Thread.currentThread().getName() + " =================================> " + i); } }
public static void main(String[] args) { ThreadDemo threadDemo1 = new ThreadDemo(); ThreadDemo threadDemo2 = new ThreadDemo(); ThreadDemo threadDemo3 = new ThreadDemo(); threadDemo1.start(); threadDemo2.start(); threadDemo3.start(); } }
|
2. 实现 runnable 接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class RunnableDemo implements Runnable { @Override public void run() { for (int i = 1; i <= 5; i++) { System.out.println(Thread.currentThread().getName() + " =================================> " + i); } }
public static void main(String[] args) { RunnableDemo runnableDemo = new RunnableDemo(); new Thread(runnableDemo, "a").start(); new Thread(runnableDemo, "b").start(); new Thread(runnableDemo, "c").start(); } }
|
这里也可以直接使用 lambda 表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public static void main(String[] args) { new Thread(()->{ for (int i = 1; i <= 50; i++) { System.out.println(Thread.currentThread().getName() + " ====> " + i); } }, "a").start(); new Thread(()->{ for (int i = 1; i <= 50; i++) { System.out.println(Thread.currentThread().getName() + " ===========> " + i); } }, "b").start(); new Thread(()->{ for (int i = 1; i <= 50; i++) { System.out.println(Thread.currentThread().getName() + " ======================> " + i); } }, "c").start(); }
|
3. 实现 callable 接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import java.util.concurrent.Callable; import java.util.concurrent.FutureTask;
public class CallableDemo implements Callable<String> { @Override public String call(){ for (int i = 1; i <= 50; i++) { System.out.println(Thread.currentThread().getName()+" "+i); } return ""; }
public static void main(String[] args) { CallableDemo callableDemo = new CallableDemo(); FutureTask<String> task = new FutureTask<>(callableDemo); new Thread(task, "a").start(); new Thread(task, "b").start(); new Thread(task, "c").start(); } }
|
4. 线程池
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class ThreadPoolDemo { public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { executorService.execute(()->{ for (int j = 0; j < 10; j++) { System.out.println(Thread.currentThread().getName()); } }); } executorService.shutdown(); } }
|
三、线程池的创建
1. 线程池七大参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public ThreadPoolExecutor(int corePoolSize, // 核心线程池大小 int maximumPoolSize, // 核心线程池大小 long keepAliveTime, // 存活时间 TimeUnit unit, // 时间单位 BlockingQueue<Runnable> workQueue, // 阻塞队列 ThreadFactory threadFactory, // 线程工厂 RejectedExecutionHandler handler // 拒绝策略) { if (corePoolSize < 0 || 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; }
|
根据阿里巴巴的Java开发手册

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| 1. Executors.newSingleThreadExecutor();
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
public LinkedBlockingQueue() { this(Integer.MAX_VALUE); }
2. Executors.newFixedThreadPool(3);
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
public LinkedBlockingQueue() { this(Integer.MAX_VALUE); }
3. Executors.newCachedThreadPool();
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
|
以上三种创建方法都默认参数填入了最大值,可能会堆积大量的请求,创建大量的线程,从而导致 OOM。
我们应该指定参数进行创建
1 2 3 4 5 6 7 8 9
| ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( 3, 5, 1, TimeUnit.MINUTES, new LinkedBlockingDeque<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy() );
|
2. 四种拒绝策略
1 2 3 4 5 6 7 8 9 10 11
| ThreadPoolExecutor.AbortPolicy();
ThreadPoolExecutor.CallerRunsPolicy();
ThreadPoolExecutor.DiscardOldestPolicy();
ThreadPoolExecutor.DiscardPolicy();
|