java基础

一. java 程序运行原理

1.class文件内容

class文件包含java程序执行的字节码;数据严格按照格式紧凑排列在class文件中的二进制流,中间无任何分隔符;文件开头由一个0xcafebabe(16进制)特殊的一个标志。
在这里插入图片描述

2.JVM运行时数据区

在这里插入图片描述

2.1 方法区

在这里插入图片描述

2.2 堆内存

在这里插入图片描述

2.3 虚拟机栈

在这里插入图片描述

2.4 本地方法栈

在这里插入图片描述

2.5 程序计数器

在这里插入图片描述

3.查看class文件内容

在这里插入图片描述

package thread.pool;

public class Demo1 {
  public Demo1() {
  }

  public static void main(String[] args) {
    int x = 500;
    int y = 100;
    int a = x / y;
    int b = 50;
    System.out.println(a + b);
  }
}

在这里插入图片描述

3.1 class内容-版本号/访问控制

在这里插入图片描述

3.2 class内容-常量池

在这里插入图片描述

3.3 class内容-构造方法

在这里插入图片描述

3.4 class内容-程序入口main方法

在这里插入图片描述

4. 程序完整运行分析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

在这里插入图片描述

二. 线程状态

java.lang.Thread.State.

  1. New:尚未启动的线程的线程状态
  2. Runnable: 可运行线程的状态,登台CPU调度
  3. Blocked: 线程阻塞等待监视器锁定的线程状态处于synchronized同步代码块或方法中被阻塞
  4. Waiting: 等待线程的线程状态。下列不带超时的方式
    Object.wait、Thread.join、 LockSupport.park
  5. Timed Waiting: 具有指定等待时间的等待线程的线程状态。下列带超时的方式:
    Thread.sleep、Object.wait、Thread.join 、LockSupport.parkNanos、LockSupport.parkUntil
  6. Terminated:终止线程的线程状态。线程正常完成执行或者出现异常。
    在这里插入图片描述
package thread.pool;

/**
 * 示例2 - 多线程运行状态切换示例 <br/>
 */
public class Demo2 {
  public static Thread thread1;
  public static Demo2 obj;

  public static void main(String[] args) throws Exception {
    // 第一种状态切换 - 新建 -> 运行 -> 终止
    System.out.println("#######第一种状态切换  - 新建 -> 运行 -> 终止################################");
    Thread thread1 = new Thread(new Runnable() {
      @Override
      public void run() {
        System.out.println("thread1当前状态:" + Thread.currentThread().getState().toString());//RUNNABLE
        System.out.println("thread1 执行了");
      }
    });
    System.out.println("没调用start方法,thread1当前状态:" + thread1.getState().toString());//NEW
    thread1.start();
    Thread.sleep(2000L); // 等待thread1执行结束,再看状态
    System.out.println("等待两秒,再看thread1当前状态:" + thread1.getState().toString());//TERMINATED
    // thread1.start(); TODO 注意,线程终止之后,再进行调用,会抛出IllegalThreadStateException异常

    System.out.println();
    System.out.println("############第二种:新建 -> 运行 -> 等待 -> 运行 -> 终止(sleep方式)###########################");
    Thread thread2 = new Thread(new Runnable() {
      @Override
      public void run() {
        try {// 将线程2移动到等待状态,1500后自动唤醒
          Thread.sleep(1500);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        System.out.println("thread2当前状态:" + Thread.currentThread().getState().toString());//RUNNABLE
        System.out.println("thread2 执行了");
      }
    });
    System.out.println("没调用start方法,thread2当前状态:" + thread2.getState().toString());//NEW
    thread2.start();
    System.out.println("调用start方法,thread2当前状态:" + thread2.getState().toString());//RUNNABLE
    Thread.sleep(200L); // 等待200毫秒,再看状态
    System.out.println("等待200毫秒,再看thread2当前状态:" + thread2.getState().toString());//TIMED_WAITING
    Thread.sleep(3000L); // 再等待3秒,让thread2执行完毕,再看状态
    System.out.println("等待3秒,再看thread2当前状态:" + thread2.getState().toString());//TIMED_WAITING

    System.out.println();
    System.out.println("############第三种:新建 -> 运行 -> 阻塞 -> 运行 -> 终止###########################");
    Thread thread3 = new Thread(new Runnable() {
      @Override
      public void run() {
        synchronized (Demo2.class) {//BLOCKED
          System.out.println("thread3当前状态:" + Thread.currentThread().getState().toString());//RUNNABLE
          System.out.println("thread3 执行了");
        }
      }
    });
    synchronized (Demo2.class) {
      System.out.println("没调用start方法,thread3当前状态:" + thread3.getState().toString());//NEW
      thread3.start();
      System.out.println("调用start方法,thread3当前状态:" + thread3.getState().toString());//RUNNABLE
      Thread.sleep(200L); // 等待200毫秒,再看状态
      System.out.println("等待200毫秒,再看thread3当前状态:" + thread3.getState().toString());//BLOCKED
    }
    Thread.sleep(3000L); // 再等待3秒,让thread3执行完毕,再看状态
    System.out.println("等待3秒,让thread3抢到锁,再看thread3当前状态:" + thread2.getState().toString());//TERMINATED

  }
}

三. 线程终止

1. 不正确的线程终止 - Stop

Stop: 终止线程,并且清除监控器锁的信息,但是可能导致线程安全问题,JDK不建议使用。(下图中i自增成功了 ,但是j自增因为线程被stop掉没有被执行)。
Destroy: JDK 未实现该方法 。

2. 正确的线程终止- Interrupt

如果目标线程在调用Object class的wait()、wait(long)或是wait(long,int)方法、join()、join(long,int)或是sleep(long,int) 方法是被阻塞,那么Interrupt会生效,该线程的中断状态将被清除,抛出InterruptedException异常。
如果目标线程是被I/O或者NIO中的Channel所阻塞,同样,I/O操作会被中断或者返回特殊异常值。达到终止线程的目的。
如果以上条件都不满足,则会设置此线程的中断状态。

public class Demo3 {
  public static void main(String[] args) throws InterruptedException {
    StopThread thread = new StopThread();
    thread.start();
    // 休眠1秒,确保i变量自增成功
    Thread.sleep(1000);
    // 暂停线程
    thread.stop(); // 错误的终止  stop线程不会抛出异常但是直接将线程终止了 ,会导致i++已经执行 j++未执行
    // thread.interrupt(); // 正确终止  抛出异常可在异常中进行代码回滚之类的操作
    while (thread.isAlive()) {
      // 确保线程已经终止
    } // 输出结果
    thread.print();
  }
}
 class StopThread extends Thread {
  private int i = 0, j = 0;

  @Override
  public void run() {
    synchronized (this) {
      // 增加同步锁,确保线程安全
      ++i;
      try {
        // 休眠10秒,模拟耗时操作
        Thread.sleep(10000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      ++j;
    }
  }

  /** * 打印i和j */
  public void print() {
    System.out.println("i=" + i + " j=" + j);
  }

3. 标志位

代码逻辑中,增加一个判断,用来控制线程执行的终止。如下

/** 通过状态位来判断 */
public class Demo4 extends Thread {
  public volatile static boolean flag = true;

  public static void main(String[] args) throws InterruptedException {
    new Thread(() -> {
      try {
        while (flag) { // 判断是否运行
          System.out.println("运行中");
          Thread.sleep(1000L);
        }
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }).start();
    // 3秒之后,将状态标志改为False,代表不继续运行
    Thread.sleep(3000L);
    flag = false;
    System.out.println("程序运行结束");
  }
}

四. 内存屏障和CPU缓存

1. CPU性能优化手段 -缓存

在这里插入图片描述

2. 多级缓存

在这里插入图片描述

3. 缓存同步协议

在这里插入图片描述

4. CPU性能优化手段 -运行时指令重排

在这里插入图片描述

5. 两个问题:

1.CPU高速缓存导致信息不同步:

	缓存中的数据和主内存的数据并不是实时同步的,各个CPU(或CPU核心)间的数据也不是实时同步。**在同一个时间点,各CPU所看到同一内存地址的数据的值可能是不一致的**。

2. CPU执行指令重排序优化导致多线程乱序执行:

 虽然遵守了as-if-serial语义,单仅在单CPU自己执行的情况下能保证结果正确。
 多核多线程中,指令逻辑无法分辨因果关联,可能出现**乱序执行**,导致程序运行结果错误

6. 内存屏障

处理器提供了两个内存屏障指令(Memory Barrier)用于解决上述两个问题:

1. 写内存屏障(Store Memory Barrier)

在指令后插入Store Barrier,能让写入缓存中的最新数据更新写入主内存,让其他线程可见。

2. 读内存屏障(Load Memory Barrier)

在指令前插入Load Barrier,可以让高速缓存中的数据失效,强制从新从主内存加载数据。

强制读取主内存内容,让CPU缓存于主内存保持一致,避免了缓存导致的一致性问题。

7. 结语

CPU不断演进,在程序运行优化中提供了很大的有利条件。
不通CPU厂商所付出的人力物力成本,最终体现在不通CPU性能差距上。

五. 线程通信

要想实现多个线程之间的协同,如:线程执行先后顺序、获取某个线程执行的结果等。涉及到线程之间相互通信,分为下面四类:
1. 文件共享
2. 网络共享
3. 共享变量
4. jdk提供的线程协调API
细分为: suspend/resume、wait/notify、park/unpark.
代码实列:

1. suspend/resume 弃用

由于容易死锁的suspend/resume已被弃用。

1 .suspend并不会像wait一样释放锁,用锁的场景容易死锁
2. suspend和resume调用有先后顺序,若resume被先执行,则会死锁

2. wait/notify

解决了suspend/resume中锁的释放问题, 线程调用wait方法后会释放锁,notify调用时可以获取倒锁,但是不能解决调用先后导致的死锁问题。
在这里插入图片描述

3. park/unpark.

park 方法是去获取是否存在许可证,unpark是放置许可证,所以解决了 suspend/resume 及wait/nofity的先后执行导致的死锁问题
park/unpark不会释放锁,容易在同步代码块中形成死锁。
在这里插入图片描述

	import java.util.concurrent.locks.LockSupport;

/** 三种线程协作通信的方式:suspend/resume、wait/notify、park/unpark */
public class Demo6 {
	/** 包子店 */
	public static Object baozidian = null;

	/** 正常的suspend/resume */
	public void suspendResumeTest() throws Exception {
		// 启动线程
		Thread consumerThread = new Thread(() -> {
			if (baozidian == null) { // 如果没包子,则进入等待
				System.out.println("1、进入等待");
				Thread.currentThread().suspend();
			}
			System.out.println("2、买到包子,回家");
		});
		consumerThread.start();
		// 3秒之后,生产一个包子
		Thread.sleep(3000L);
		baozidian = new Object();
		consumerThread.resume();
		System.out.println("3、通知消费者");
	}

	/** 死锁的suspend/resume。 suspend并不会像wait一样释放锁,故此容易写出死锁代码 */
	public void suspendResumeDeadLockTest() throws Exception {
		// 启动线程
		Thread consumerThread = new Thread(() -> {
			if (baozidian == null) { // 如果没包子,则进入等待
				System.out.println("1、进入等待");
				// 当前线程拿到锁,然后挂起
				synchronized (this) {
					Thread.currentThread().suspend();
				}
			}
			System.out.println("2、买到包子,回家");
		});
		consumerThread.start();
		// 3秒之后,生产一个包子
		Thread.sleep(3000L);
		baozidian = new Object();
		// 争取到锁以后,再恢复consumerThread
		synchronized (this) {
			consumerThread.resume();
		}
		System.out.println("3、通知消费者");
	}

	/** 导致程序永久挂起的suspend/resume */
	public void suspendResumeDeadLockTest2() throws Exception {
		// 启动线程
		Thread consumerThread = new Thread(() -> {
			if (baozidian == null) {
				System.out.println("1、没包子,进入等待");
				try { // 为这个线程加上一点延时
					Thread.sleep(5000L);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				// 这里的挂起执行在resume后面
				Thread.currentThread().suspend();
			}
			System.out.println("2、买到包子,回家");
		});
		consumerThread.start();
		// 3秒之后,生产一个包子
		Thread.sleep(3000L);
		baozidian = new Object();
		consumerThread.resume();
		System.out.println("3、通知消费者");
		consumerThread.join();
	}

	/** 正常的wait/notify */
	public void waitNotifyTest() throws Exception {
		// 启动线程
		new Thread(() -> {
			if (baozidian == null) { // 如果没包子,则进入等待
				synchronized (this) {
					try {
						System.out.println("1、进入等待");
						this.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
			System.out.println("2、买到包子,回家");
		}).start();
		// 3秒之后,生产一个包子
		Thread.sleep(3000L);
		baozidian = new Object();
		synchronized (this) {
			this.notifyAll();
			System.out.println("3、通知消费者");
		}
	}

	/** 会导致程序永久等待的wait/notify */
	public void waitNotifyDeadLockTest() throws Exception {
		// 启动线程
		new Thread(() -> {
			if (baozidian == null) { // 如果没包子,则进入等待
				try {
					Thread.sleep(5000L);
				} catch (InterruptedException e1) {
					e1.printStackTrace();
				}
				synchronized (this) {
					try {
						System.out.println("1、进入等待");
						this.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
			System.out.println("2、买到包子,回家");
		}).start();
		// 3秒之后,生产一个包子
		Thread.sleep(3000L);
		baozidian = new Object();
		synchronized (this) {
			this.notifyAll();
			System.out.println("3、通知消费者");
		}
	}

	/** 正常的park/unpark */
	public void parkUnparkTest() throws Exception {
		// 启动线程
		Thread consumerThread = new Thread(() -> {
			if (baozidian == null) { // 如果没包子,则进入等待
				System.out.println("1、进入等待");
				LockSupport.park();
			}
			System.out.println("2、买到包子,回家");
		});
		consumerThread.start();
		// 3秒之后,生产一个包子
		Thread.sleep(3000L);
		baozidian = new Object();
		LockSupport.unpark(consumerThread);
		System.out.println("3、通知消费者");
	}

	/** 死锁的park/unpark */
	public void parkUnparkDeadLockTest() throws Exception {
		// 启动线程
		Thread consumerThread = new Thread(() -> {
			if (baozidian == null) { // 如果没包子,则进入等待
				System.out.println("1、进入等待");
				// 当前线程拿到锁,然后挂起
				synchronized (this) {
					LockSupport.park();
				}
			}
			System.out.println("2、买到包子,回家");
		});
		consumerThread.start();
		// 3秒之后,生产一个包子
		Thread.sleep(3000L);
		baozidian = new Object();
		// 争取到锁以后,再恢复consumerThread
		synchronized (this) {
			LockSupport.unpark(consumerThread);
		}
		System.out.println("3、通知消费者");
	}

	public static void main(String[] args) throws Exception {
		// 对调用顺序有要求,也要开发自己注意锁的释放。这个被弃用的API, 容易死锁,也容易导致永久挂起。
		// new Demo6().suspendResumeTest();
		// new Demo6().suspendResumeDeadLockTest();
		// new Demo6().suspendResumeDeadLockTest2();

		// wait/notify要求再同步关键字里面使用,免去了死锁的困扰,但是一定要先调用wait,再调用notify,否则永久等待了
		// new Demo6().waitNotifyTest();
		// new Demo6().waitNotifyDeadLockTest();

		// park/unpark没有顺序要求,但是park并不会释放锁,所有再同步代码中使用要注意
		// new Demo6().parkUnparkTest();
		// new Demo6().parkUnparkDeadLockTest();

	}
}

4. 伪唤醒

在这里插入图片描述

六. 线程封闭

1. 概念

多线程访问共享数据时,涉及到线程间数据同步的问题。并不是所有时候,都要用到共享数据,所以线程封闭概念就提出来了。
数据都被封闭在各子的线程之中,就不需要同步,这种通过将数据封闭再线程中而避免使用同步的技术称为 **线程封闭**。
线程封闭具体的体现又: ThreadLocal、局部变量.

2. ThreadLocal

ThreadLocal是java里一种特殊的变量, 他是一个线程级别的变量,每个线程都有一个ThreadLocal就是每个线程都拥有自己独立的变量,竞争条件被彻底消除,再并发模式下是绝对安全的变量。
用法: ThreadLocal var=new ThreadLocal();
会自动再每一个线程上创建一个T的副本,副本之间彼此独立,互不影响
可以用ThreadLocal存储一些参数,以便在线程中多个方法中使用,用来代替方法传参的做法
** 实在难以理解的,可以理解为,JVM维护了一个Map<Thread,T>,每个线程要用T的时候都用thred去map中取。仅作为一个概念理解。

/** 线程封闭示例 */
public class Demo5 {
	/** threadLocal变量,每个线程都有一个副本,互不干扰 */
	public static ThreadLocal<String> value = new ThreadLocal<>();

	/**
	 * threadlocal测试
	 * 
	 * @throws Exception
	 */
	public void threadLocalTest() throws Exception {

		// threadlocal线程封闭示例
		value.set("这是主线程设置的123"); // 主线程设置值
		String v = value.get();
		System.out.println("线程1执行之前,主线程取到的值:" + v);

		new Thread(new Runnable() {
			@Override
			public void run() {
				String v = value.get();
				System.out.println("线程1取到的值:" + v);
				// 设置 threadLocal
				value.set("这是线程1设置的456");

				v = value.get();
				System.out.println("重新设置之后,线程1取到的值:" + v);
				System.out.println("线程1执行结束");
			}
		}).start();

		Thread.sleep(5000L); // 等待所有线程执行结束

		v = value.get();
		System.out.println("线程1执行之后,主线程取到的值:" + v);

	}

	public static void main(String[] args) throws Exception {
		new Demo5().threadLocalTest();
	}
}

3. 栈封闭

局部变量的固有属性之一就是封闭在线程中。
他们位于执行线程的栈中,其他线程无法访问这个栈。

七. 线程池应用及实现

1. 为什么要用线程池

在这里插入图片描述

2.线程池原理-概念

在这里插入图片描述

3. 线程池api

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package thread.pool;

import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 线程池的使用
 * @larzhu
 * @2021/5/20
 *
 */


public class Demo9 {

  /**
   * 测试: 提交15个执行时间需要3秒的任务,看线程池的状况
   *
   * @param threadPoolExecutor 传入不同的线程池,看不同的结果
   * @throws Exception
   */
  public void testCommon(ThreadPoolExecutor threadPoolExecutor) throws Exception {
    // 测试: 提交15个执行时间需要3秒的任务,看超过大小的2个,对应的处理情况
    for (int i = 0; i < 15; i++) {
      int n = i;
      threadPoolExecutor.submit(new Runnable() {
        @Override
        public void run() {
          try {
            System.out.println("开始执行:" + n);
            Thread.sleep(3000L);
            System.err.println("执行结束:" + n);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      });
      System.out.println("任务提交成功 :" + i);
    }
    // 查看线程数量,查看队列等待数量
    Thread.sleep(500L);
    System.out.println("当前线程池线程数量为:" + threadPoolExecutor.getPoolSize());
    System.out.println("当前线程池等待的数量为:" + threadPoolExecutor.getQueue().size());
    // 等待15秒,查看线程数量和队列数量(理论上,会被超出核心线程数量的线程自动销毁)
    Thread.sleep(15000L);
    System.out.println("当前线程池线程数量为:" + threadPoolExecutor.getPoolSize());
    System.out.println("当前线程池等待的数量为:" + threadPoolExecutor.getQueue().size());
  }

  /**
   * 1、线程池信息: 核心线程数量5,最大数量10,无界队列,超出核心线程数量的线程存活时间:5秒, 指定拒绝策略的
   *
   * @throws Exception
   */
  private void threadPoolExecutorTest1() throws Exception {
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
        new LinkedBlockingQueue<Runnable>());
    testCommon(threadPoolExecutor);
    // 预计结果:线程池线程数量为:5,超出数量的任务,其他的进入队列中等待被执行
  }

  /**
   * 2、 线程池信息: 核心线程数量5,最大数量10,队列大小3,超出核心线程数量的线程存活时间:5秒, 指定拒绝策略的
   *
   * @throws Exception
   */
  private void threadPoolExecutorTest2() throws Exception {
    // 创建一个 核心线程数量为5,最大数量为10,等待队列最大是3 的线程池,也就是最大容纳13个任务。
    // 默认的策略是抛出RejectedExecutionException异常,java.util.concurrent.ThreadPoolExecutor.AbortPolicy
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
        new LinkedBlockingQueue<Runnable>(3), new RejectedExecutionHandler() {
      @Override
      public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        System.err.println("有任务被拒绝执行了");
      }
    });
    testCommon(threadPoolExecutor);
    // 预计结果:
    // 1、 5个任务直接分配线程开始执行
    // 2、 3个任务进入等待队列
    // 3、 队列不够用,临时加开5个线程来执行任务(5秒没活干就销毁)
    // 4、 队列和线程池都满了,剩下2个任务,没资源了,被拒绝执行。
    // 5、 任务执行,5秒后,如果无任务可执行,销毁临时创建的5个线程
  }

  /**
   * 3、 线程池信息: 核心线程数量5,最大数量5,无界队列,超出核心线程数量的线程存活时间:5秒
   *
   * @throws Exception
   */
  private void threadPoolExecutorTest3() throws Exception {
    // 和Executors.newFixedThreadPool(int nThreads)一样的
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS,
        new LinkedBlockingQueue<Runnable>());
    testCommon(threadPoolExecutor);
    // 预计结:线程池线程数量为:5,超出数量的任务,其他的进入队列中等待被执行
  }

  /**
   * 4、 线程池信息:
   * 核心线程数量0,最大数量Integer.MAX_VALUE,SynchronousQueue队列,超出核心线程数量的线程存活时间:60秒
   *
   * @throws Exception
   */
  private void threadPoolExecutorTest4() throws Exception {

    // SynchronousQueue,实际上它不是一个真正的队列,因为它不会为队列中元素维护存储空间。与其他队列不同的是,它维护一组线程,这些线程在等待着把元素加入或移出队列。
    // 在使用SynchronousQueue作为工作队列的前提下,客户端代码向线程池提交任务时,
    // 而线程池中又没有空闲的线程能够从SynchronousQueue队列实例中取一个任务,
    // 那么相应的offer方法调用就会失败(即任务没有被存入工作队列)。
    // 此时,ThreadPoolExecutor会新建一个新的工作者线程用于对这个入队列失败的任务进行处理(假设此时线程池的大小还未达到其最大线程池大小maximumPoolSize)。

    // 和Executors.newCachedThreadPool()一样的
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
        new SynchronousQueue<Runnable>());
    testCommon(threadPoolExecutor);
    // 预计结果:
    // 1、 线程池线程数量为:15,超出数量的任务,其他的进入队列中等待被执行
    // 2、 所有任务执行结束,60秒后,如果无任务可执行,所有线程全部被销毁,池的大小恢复为0
    Thread.sleep(60000L);
    System.out.println("60秒后,再看线程池中的数量:" + threadPoolExecutor.getPoolSize());
  }

  /**
   * 5、 定时执行线程池信息:3秒后执行,一次性任务,到点就执行 <br/>
   * 核心线程数量5,最大数量Integer.MAX_VALUE,DelayedWorkQueue延时队列,超出核心线程数量的线程存活时间:0秒
   *
   * @throws Exception
   */
  private void threadPoolExecutorTest5() throws Exception {
    // 和Executors.newScheduledThreadPool()一样的
    ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(5);
    threadPoolExecutor.schedule(new Runnable() {
      @Override
      public void run() {
        System.out.println("任务被执行,现在时间:" + System.currentTimeMillis());
      }
    }, 3000, TimeUnit.MILLISECONDS);
    System.out.println(
        "定时任务,提交成功,时间是:" + System.currentTimeMillis() + ", 当前线程池中线程数量:" + threadPoolExecutor.getPoolSize());
    // 预计结果:任务在3秒后被执行一次
  }

  /**
   * 6、 定时执行线程池信息:线程固定数量5 ,<br/>
   * 核心线程数量5,最大数量Integer.MAX_VALUE,DelayedWorkQueue延时队列,超出核心线程数量的线程存活时间:0秒
   *
   * @throws Exception
   */
  private void threadPoolExecutorTest6() throws Exception {
    ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(5);
    // 周期性执行某一个任务,线程池提供了两种调度方式,这里单独演示一下。测试场景一样。
    // 测试场景:提交的任务需要3秒才能执行完毕。看两种不同调度方式的区别
    // 效果1: 提交后,2秒后开始第一次执行,之后每间隔1秒,固定执行一次(如果发现上次执行还未完毕,则等待完毕,完毕后立刻执行)。
    // 也就是说这个代码中是,3秒钟执行一次(计算方式:每次执行三秒,间隔时间1秒,执行结束后马上开始下一次执行,无需等待)
    threadPoolExecutor.scheduleAtFixedRate(new Runnable() {
      @Override
      public void run() {
        try {
          Thread.sleep(3000L);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        System.out.println("任务-1 被执行,现在时间:" + System.currentTimeMillis());
      }
    }, 2000, 1000, TimeUnit.MILLISECONDS);

    // 效果2:提交后,2秒后开始第一次执行,之后每间隔1秒,固定执行一次(如果发现上次执行还未完毕,则等待完毕,等上一次执行完毕后再开始计时,等待1秒)。
    // 也就是说这个代码钟的效果看到的是:4秒执行一次。 (计算方式:每次执行3秒,间隔时间1秒,执行完以后再等待1秒,所以是 3+1)
    threadPoolExecutor.scheduleWithFixedDelay(new Runnable() {
      @Override
      public void run() {
        try {
          Thread.sleep(3000L);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        System.out.println("任务-2 被执行,现在时间:" + System.currentTimeMillis());
      }
    }, 2000, 1000, TimeUnit.MILLISECONDS);
  }

  /**
   * 7、 终止线程:线程池信息: 核心线程数量5,最大数量10,队列大小3,超出核心线程数量的线程存活时间:5秒, 指定拒绝策略的
   *
   * @throws Exception
   */
  private void threadPoolExecutorTest7() throws Exception {
    // 创建一个 核心线程数量为5,最大数量为10,等待队列最大是3 的线程池,也就是最大容纳13个任务。
    // 默认的策略是抛出RejectedExecutionException异常,java.util.concurrent.ThreadPoolExecutor.AbortPolicy
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
        new LinkedBlockingQueue<Runnable>(3), new RejectedExecutionHandler() {
      @Override
      public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        System.err.println("有任务被拒绝执行了");
      }
    });
    // 测试: 提交15个执行时间需要3秒的任务,看超过大小的2个,对应的处理情况
    for (int i = 0; i < 15; i++) {
      int n = i;
      threadPoolExecutor.submit(new Runnable() {
        @Override
        public void run() {
          try {
            System.out.println("开始执行:" + n);
            Thread.sleep(3000L);
            System.err.println("执行结束:" + n);
          } catch (InterruptedException e) {
            System.out.println("异常:" + e.getMessage());
          }
        }
      });
      System.out.println("任务提交成功 :" + i);
    }
    // 1秒后终止线程池
    Thread.sleep(1000L);
    threadPoolExecutor.shutdown();
    // 再次提交提示失败
    threadPoolExecutor.submit(new Runnable() {
      @Override
      public void run() {
        System.out.println("追加一个任务");
      }
    });
    // 结果分析
    // 1、 10个任务被执行,3个任务进入队列等待,2个任务被拒绝执行
    // 2、调用shutdown后,不接收新的任务,等待13任务执行结束
    // 3、 追加的任务在线程池关闭后,无法再提交,会被拒绝执行
  }

  /**
   * 8、 立刻终止线程:线程池信息: 核心线程数量5,最大数量10,队列大小3,超出核心线程数量的线程存活时间:5秒, 指定拒绝策略的
   *
   * @throws Exception
   */
  private void threadPoolExecutorTest8() throws Exception {
    // 创建一个 核心线程数量为5,最大数量为10,等待队列最大是3 的线程池,也就是最大容纳13个任务。
    // 默认的策略是抛出RejectedExecutionException异常,java.util.concurrent.ThreadPoolExecutor.AbortPolicy
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
        new LinkedBlockingQueue<Runnable>(3), new RejectedExecutionHandler() {
      @Override
      public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        System.err.println("有任务被拒绝执行了");
      }
    });
    // 测试: 提交15个执行时间需要3秒的任务,看超过大小的2个,对应的处理情况
    for (int i = 0; i < 15; i++) {
      int n = i;
      threadPoolExecutor.submit(new Runnable() {
        @Override
        public void run() {
          try {
            System.out.println("开始执行:" + n);
            Thread.sleep(3000L);
            System.err.println("执行结束:" + n);
          } catch (InterruptedException e) {
            System.out.println("异常:" + e.getMessage());
          }
        }
      });
      System.out.println("任务提交成功 :" + i);
    }
    // 1秒后终止线程池
    Thread.sleep(1000L);
    List<Runnable> shutdownNow = threadPoolExecutor.shutdownNow();
    // 再次提交提示失败
    threadPoolExecutor.submit(new Runnable() {
      @Override
      public void run() {
        System.out.println("追加一个任务");
      }
    });
    System.out.println("未结束的任务有:" + shutdownNow.size());

    // 结果分析
    // 1、 10个任务被执行,3个任务进入队列等待,2个任务被拒绝执行
    // 2、调用shutdownnow后,队列中的3个线程不再执行,10个线程被终止
    // 3、 追加的任务在线程池关闭后,无法再提交,会被拒绝执行
  }

  public static void main(String[] args) throws Exception {
    new Demo9().threadPoolExecutorTest1();
//		new Demo9().threadPoolExecutorTest2();
//		new Demo9().threadPoolExecutorTest3();
//		new Demo9().threadPoolExecutorTest4();
//		new Demo9().threadPoolExecutorTest5();
//		new Demo9().threadPoolExecutorTest6();
//		new Demo9().threadPoolExecutorTest7();
//		new Demo9().threadPoolExecutorTest8();
  }
}

4.线程池原理-任务execute过程

在这里插入图片描述

5. 线程数量

监控cpu的指标80%左右极为合理,太低则利用率太低了
在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值