文章目录
多线程
进程和线程 (Process and Thread)
- 程序,程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念
- 进程,进程是执行程序的一次执行过程,它是一个动态的概念,是系统资源分配的单位
- 线程,通常一个进程可以包含若干个线程,当然一个进程至少有一个线程,线程是cpu调度和执行的单位
- 很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核.
线程
- 线程就是独立的执行路径
- 在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程、gc线程
- main()称为主线程,为系统的入口,用于执行整个程序
- 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为干涉的.
- 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制
- 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致
- 线程会带来额外开销,如cpu调度时间,并发控制开销
实现线程的三种方式
- 避免单继承局限性,推荐使用Runnable接口实现
继承Thread类
/**
* 多线程实现一: 1. 继承Thread类.
* 2.重写run方法,编写线程执行体
* 3.创建线程对象,调用start方法启动线程
*
* 注: 线程开启不一定立即执行,由cpu调度决定
*/
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("我爱学习"+i);
}
}
public static void main(String[] args) {
//开启线程
new MyThread().start();
for (int i = 0; i < 1000; i++) {
System.out.println("你不爱学习"+i);
}
}
}
例子: 通过url下载图片
//下载网图
public class MyThreadTest extends Thread{
private URL url; //图片地址
private String name; //下载下来图片名称
public MyThreadTest(URL url,String name) {
this.url = url;
this.name = name;
}
@Override
public void run() {
try {
new Download().down(url,name);
System.out.println("下载的文件名为"+name);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
URL url = new URL("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic23" +
".nipic.com%2F20120730%2F8820441_171402261000_2.jpg&refer=http%3A%2F%2Fpic23." +
"nipic.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg? sec=1633077226&t=374063ccb6acc22d274616a58a359dd0");
new MyThreadTest(url,"1.jpg").start();
new MyThreadTest(url,"2.jpg").start();
new MyThreadTest(url,"3.jpg").start();
}
}
//下载器
class Download{
public void down(URL url, String name) throws IOException {
//使用commons-io包提供的方法
FileUtils.copyURLToFile(url,new File(name),5000,5000);
}
}
实现Runable接口
/**
* 多线程实现方式二: 1.实现Runnable接口
* 2.重写run方法.编写线程执行体
* 3.将对象传入Thread对象,调用start方法启动线程
*/
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("runnable实现"+i);
}
}
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable();
new Thread(runnable,"新开线程1").start();
for (int i = 0; i < 100; i++) {
System.out.println("main主线程"+i);
}
}
}
例子:龟兔赛跑
//龟兔赛跑
public class Race implements Runnable{
//确定唯一胜利者,当有胜利者时,剩余线程不用执行
public static String winner;
@Override
public void run() {
for (int i = 0; i <= 5; i++) {
boolean b = gameOver(i);
if (b){
break;
}
if (Thread.currentThread().getName().equals("兔子") && i%10==0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"跑了-->"+i+"步");
}
}
public boolean gameOver(int i){
if (winner != null){
return true;
}
if (i >= 5) {
winner = Thread.currentThread().getName();
System.out.println("胜利者是--->"+winner);
return true;
}
return false;
}
public static void main(String[] args) {
Race race = new Race();
new Thread(race,"乌龟").start();
new Thread(race,"兔子").start();
}
}
/*打印结果
乌龟跑了-->0步
乌龟跑了-->1步
乌龟跑了-->2步
乌龟跑了-->3步
乌龟跑了-->4步
胜利者是--->乌龟
兔子跑了-->0步
*/
为什么结尾还有一个兔子跑了-->0步?
==> 兔子线程在乌龟跑到5的时候就已经启动过,但是sleep了.因为判断是否已经gameOver在线程sleep上面执行---调换位置即可
@Override
public void run() {
for (int i = 0; i <= 5; i++) {
if (Thread.currentThread().getName().equals("兔子") && i%10==0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//胜利者是否诞生
boolean b = gameOver(i);
if (b){
break;
}
System.out.println(Thread.currentThread().getName()+"跑了-->"+i+"步");
}
}
实现Callable接口
- 好处: 1. 可以定义返回值
-
- 可以抛出异常
/**
多线程实现方式三: 1.实现Callable接口
2.重写call方法,需要抛出异常
3.创建目标对象
4.创建执行服务
5.提交执行
6.获取结果
7.关闭服务
*/
public class ThreadTest implements Callable<Boolean> {
@Override
public Boolean call() throws Exception {
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建目标对象
ThreadTest threadTest = new ThreadTest();
//创建执行服务
ExecutorService service = Executors.newFixedThreadPool(1);
//提交执行
Future future = service.submit(threadTest);
//获取结果
boolean b = (boolean) future.get();
System.out.println(b);
//关闭服务
service.shutdownNow();
}
}
静态代理
/*
静态代理:
真实对象和代理对象实现同一个接口
代理对象要代理真实角色
好处:
代理对象对真实对象进行功能升级
真实对象专注做自己的事情
*/
public class StaticProxy {
public static void main(String[] args) {
/* You you = new You();
WeddingCompany weddingCompany = new WeddingCompany(you);
weddingCompany.happyMarry();*/
new WeddingCompany(new You()).happyMarry();
}
}
interface Marry{
void happyMarry();
}
//真实角色
class You implements Marry{
@Override
public void happyMarry() {
System.out.println("张某人快乐.结婚");
}
}
//代理角色
class WeddingCompany implements Marry{
private Marry targer;
public WeddingCompany(Marry targer) {
this.targer = targer;
}
@Override
public void happyMarry() {
before();
this.targer.happyMarry();
after();
}
private void after() {
System.out.println("婚礼结束,收尾款");
}
private void before() {
System.out.println("婚礼之前,布置现场");
}
}
Thread底层实现方式
比较:
new WeddingCompany(new You()).happyMarry(); //静态代理模式
new Thread(runnable,“新开线程1”).start(); //线程开启Runnable方式
Thread底层就是基于静态代理模式
Lamda表达式
- 想使用lamda表达式,接口必须满足函数式接口
- 函数式接口 —> 接口中只有一个抽象方法
- lamda表达式 —>简化代码
lamda进化过程
public class LambdaEvolve {
//2.静态内部类方式
static class Student2 implements Person{
@Override
public void lambda() {
System.out.println("学习lambda很快乐2");
}
}
public static void main(String[] args) {
Person student;
//1.实现接口方式
student = new Student();
student.lambda();
//2.静态内部类方式
student = new Student2();
student.lambda();
//3.局部内部类方式
class Student3 implements Person{
@Override
public void lambda() {
System.out.println("学习lambda很快乐3");
}
}
student = new Student3();
student.lambda();
//4.匿名内部类方式
student = new Person() {
@Override
public void lambda() {
System.out.println("学习lambda很快乐4");
}
};
student.lambda();
//5. lambda表达式方式
student = ()->{System.out.println("学习lambda很快乐5");};
student.lambda();
}
}
//定义函数式接口
interface Person{
void lambda();
}
//定义实体类实现
class Student implements Person{
@Override
public void lambda() {
System.out.println("学习lambda很快乐");
}
}
lamda简化过程
public class LambdaSimoLify {
//前提: 函数式接口
public static void main(String[] args) {
TestLamda testLamda;
//普通版
testLamda = (int a)->{System.out.println("你好"+a);};
//简化1:参数类型 --->多个参数,参数类型去掉就都去掉
testLamda = (a)->{System.out.println("你好"+a);};
//简化2:简化括号 --->只有一个参数才行
testLamda = a->{System.out.println("你好"+a);};
//简化3: 去掉花括号 -->只有一行代码时才可以
testLamda = a->System.out.println("你好"+a);
testLamda.test(5);
//综上: 推荐使用:
testLamda = (a)->{System.out.println("你好"+a);};
}
}
interface TestLamda{
void test(int a);
}
线程操作
线程状态
线程状态观测
Thread.State
- NEW 尚未启动的线程处于此状态
- RUNNABLE 在JAVA虚拟机中执行的线程处于此状态
- BLOCKED 被阻塞等待监视器锁定的线程处于此状态
- WAITING 正在等待另一个线程执行特定动作的线程处于此状态
- TIMED_WAITING 正在等待另外一个线程执行动作达到指定等待时间的线程处于此状态
- TERMINATED 已退出的线程处于此状态
//线程状态
public class ThreadState {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"线程运行");
});
//观察状态NEW
Thread.State state = thread.getState();
System.out.println(state);
//观察启动后状态 RUNNABLE
thread.start();
state = thread.getState();
System.out.println(state);
while (state != Thread.State.TERMINATED){
Thread.sleep(100);
state = thread.getState();
System.out.println(state);
}
}
}
线程停止
- 不推荐使用JDK提供的stop()、destory()方法 [已废弃] -->下面有说明
- 推荐线程自己停下来
- 使用标志位进行控制
public class TestStop implements Runnable{
//使用标志位让线程停下来
private boolean flag = true;
@Override
public void run() {
while (flag){
System.out.println("thread is run....");
}
}
//自定义stop方法
public void stop(){
this.flag = false;
}
public static void main(String[] args) {
TestStop ts = new TestStop();
new Thread(ts).start();
for (int i = 0; i < 500; i++) {
if (i == 400){
ts.stop();
System.out.println("线程停止");
}
System.out.println("main线程++"+i);
}
}
}
线程停止为什么不推荐使用stop()和distory()方法?
stop(): 此方法可以强行终止一个正在运行或挂起的线程。但stop方法不安全,就像强行切断计算机电源,而不是正常程序关机,可能会产生不可预料的结果
举例来说:
当一个线程对象上调用stop()方法时,这个线程对象所运行的线程就会立即停止,并抛出特殊的ThreadDeath()异常。这里的"立即"因为太"立即"了。
假如一个线程正在执行:synchronized void { x = 3; y = 4; }
由于方法时同步的,多个线程访问时总能保证想x,y被同时赋值,而如果一个线程正在执行到x=3时,被调用了 stop()方法,即使在同步块中,它也干脆地stop了,这样就产生了不完整的残废数据。而多线程编程中最最基础的条件要保证数据的完整性,所以请忘记 线程的stop方法,以后我们再也不要说“停止线程”了。
destroy():该方法最初用于破坏该线程,但不作任何资源释放。它所保持的任何监视器都会保持锁定状态。不过,该方法决不会被实现。即使要实现,它也极有可能以 suspend() 方式被死锁。如果目标线程被破坏时保持一个保护关键系统资源的锁,则任何线程在任何时候都无法再次访问该资源。如果另一个线程曾试图锁定该资源,则会出现死锁。
线程休眠_sleep
每一个对象都有一个锁,sleep不会释放锁
//网络延时:放大问题的发生性
public class TestSleep {
public static void main(String[] args) throws InterruptedException {
//模拟倒计时
tenDown();
//每隔一秒打印系统时间
Date date = new Date();
while(true){
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));
Thread.sleep(1000);
date = new Date();
}
}
public static void tenDown() throws InterruptedException {
int num = 10;
while(true){
System.out.println(num--);
Thread.sleep(1000);
if (num <= 0){
break;
}
}
}
}
线程礼让_yield
//礼让不一定成功,看cpu心情
public class TestYield {
public static void main(String[] args) {
Runnable thread = ()->{
System.out.println(Thread.currentThread().getName()+"-->开始执行");
//礼让
Thread.yield();
System.out.println(Thread.currentThread().getName()+"-->结束执行");
};
new Thread(thread,"a").start();
new Thread(thread,"b").start();
}
}
线程强制执行_Join
/**
* Join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞
* 可以理解为 --->插队
*/
public class TestJoin {
public static void main(String[] args) throws InterruptedException {
Runnable td = ()->{
for (int i = 0; i < 10; i++) {
System.out.println("vip线程来哦"+i);
}
};
Thread thread = new Thread(td);
thread.start();
for (int i = 0; i < 20; i++) {
if (i == 10){
//线程强制执行
thread.join();
}
System.out.println("main线程"+i);
}
}
}
线程优先级_priority
//设置线程优先级 默认5
public class ThreadPriority {
public static void main(String[] args) {
Runnable runnable = ()-> System.out.println(Thread.currentThread().getName()+"线程运行,优先级+"+Thread.currentThread().getPriority());
//主线程main
System.out.println(Thread.currentThread().getName()+"线程运行,优先级+"+Thread.currentThread().getPriority());
Thread thread = new Thread(runnable);
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(runnable);
Thread thread3 = new Thread(runnable);
Thread thread4 = new Thread(runnable);
thread.setPriority(Thread.MIN_PRIORITY);
thread.start();
thread1.setPriority(1);
thread1.start();
thread2.setPriority(2);
thread2.start();
thread3.setPriority(3);
thread3.start();
thread4.setPriority(Thread.MAX_PRIORITY);
thread4.start();
}
}
守护线程_deamon
- 线程分为 用户线程 和守护线程
- 虚拟机必须确保用户线程执行完毕
- 虚拟机不用等待守护线程执行完毕
- 如,后台记录操作,监控内存,垃圾回收等
//测试守护线程
public class ThreadDaemon {
public static void main(String[] args) {
God god = new God();
You you = new You();
//设置上帝为守护线程
Thread thread = new Thread(god);
thread.setDaemon(true); //默认是 false 表示用户线程.正常的线程都是用户线程
thread.start();
//启动you
new Thread(you).start();
/*
当you 线程输出 goodbye 结束线程时.
god线程也会输出几句然后关闭 (虚拟机关闭需要时间)
*/
}
}
class God implements Runnable{
@Override
public void run() {
while (true){
System.out.println("上帝与你同在.....");
}
}
}
class You implements Runnable{
@Override
public void run() {
for (int i = 0; i < 36500; i++) {
System.out.println("你在世第.."+i+"天");
}
System.out.println("goodbye word!");
}
}
线程同步
**并发:** ==同一个对象被多个线程同时操作==
**线程同步:** 解决并发问题 ----> ==排队(队列) +锁==
**锁机制Synchronized:** 线程获得对象锁,其他线程只能等待,等锁释放后在获取锁进入
问题: 1.性能变差 2.有可能产生性能倒置问题
// 并发问题 模拟 ---->抢票 --->核心原因 线程都有自己的工作内存
// -->同时操作一个资源,都将资源带入自己的工作内存交互, 当票数为1时.两个线程都将1带入自己线程交互,结果出现了0
public class TestTicket implements Runnable {
private int ticket = 10;
@Override
public void run() {
while(ticket >=1){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到第"+ticket-- + "张票");
}
}
public static void main(String[] args) {
TestTicket ticket = new TestTicket();
Thread thread = new Thread(ticket, "a");
Thread thread2 = new Thread(ticket, "b");
thread.start();
thread2.start();
}
}
/**
* a抢到第9张票
* b抢到第10张票
* a抢到第8张票
* b抢到第7张票
* a抢到第6张票
* b抢到第6张票
* b抢到第5张票
* a抢到第4张票
* a抢到第3张票
* b抢到第2张票
* a抢到第1张票
* b抢到第0张票 可看出,当多个线程操作同一资源时,时不安全的
*/
//ArrayList线程不安全
public class UnsafeThreadList {
public static void main(String[] args) throws InterruptedException {
List<String> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
new Thread( ()-> list.add(Thread.currentThread().getName())).start();
}
Thread.sleep(5000);
System.out.println(list.size()); //9998
}
}
同步方法,同步代码块
synchronized默认锁是当前类对象------每个对象都对应一把锁
- 同步方法
public synchronized void method(int args){}
同步方法 限制–> 因为syncronized在方法上获取的锁是当前类的锁,当你对别的类中的数据作出改变,synchronized关键字没用
so —同步代码块出
- 同步代码块
synchronized (obj){} obj代表你需要增删改查的对象,让其线程同步.
//同步方法的使用
public class ThreadTest implements Runnable{
private int ticket = 10;
@Override
public synchronized void run() {
while(ticket >=1){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到第"+ticket-- + "张票");
}
}
//同步代码块的使用
List<String> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
synchronized (list){
new Thread( ()-> list.add(Thread.currentThread().getName())).start();
}
}
死锁
- 多个线程互相抱着对方需要的资源,然后形成僵持
- 某一个同步块**同时拥有两个以上对象的锁**就有可能产生死锁
public class DeadLock {
public static void main(String[] args) {
Makeup g1 = new Makeup(0, "灰姑凉");
Makeup g2 = new Makeup(1, "灰姑凉");
g1.start();
g2.start();
}
}
//口红
class Lipstick{ }
//镜子
class Mirror{ }
class Makeup extends Thread{
static Lipstick lipstick = new Lipstick(); //保证锁对象的唯一性
static Mirror mirror = new Mirror();
private int choice;
private String girlName;
public Makeup(int choice, String girlName){
this.choice = choice;
this.girlName = girlName;
}
@Override
public void run() {
//化妆
try {
makeup();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//化妆
private void makeup() throws InterruptedException {
if (choice == 0) {
synchronized (lipstick){ //获取锁所对象 口红
System.out.println(this.girlName+"获得口红");
Thread.sleep(1000);
synchronized (mirror){
System.out.println(this.girlName+"获得镜子");
}
}
}else{
synchronized (mirror){
System.out.println(this.girlName+"获得镜子");
Thread.sleep(2000);
synchronized (lipstick){
System.out.println(this.girlName+"获得口红");
}
}
}
}
}
/*
灰姑凉获得口红
灰姑凉获得镜子
卡主了...
*/
Lock锁
- lock是显示锁,synchronized是隐式锁
- 一般使用子类 ReentrantLock来 可重入锁
- Lock > 同步代码块 > 同步方法 (效率上来说)
public class TestLock {
public static void main(String[] args) {
TicketTest ticketTest = new TicketTest();
new Thread(ticketTest).start();
new Thread(ticketTest).start();
new Thread(ticketTest).start();
}
}
class TicketTest implements Runnable{
private int ticket = 10;
private final Lock lock = new ReentrantLock();
@Override
public void run() {
try{
lock.lock();//开启锁
while (ticket > 0){
System.out.println(ticket--);
}
}finally {
lock.unlock(); //释放锁
}
}
}
线程通信
-
线程通信 ----> 生产者or消费者: 生产者–生产–> 东西 <–消费–消费者消费
-
线程通信: 这是一个线程问题,生产者和消费者共享同一资源,并且生产者和消费者之间相互依赖,互为条件
-
synchronized 可组织并发更新同一个共享资源,实现同步…却不能实现不同线程之间的信息传递(通信)
解决方法:
一: 管程法
生产者将生产好的数据放入 **缓冲区**, 消费者从**缓冲区**拿出数据
二: 信号灯法
给一个标志符 ,, 有消费者消费,无,消费者等待
- 线程通信方法
方法名 | 作用 |
---|---|
wait() | 表示线程一直等待,直到其他线程通知,与sleep不同,会释放锁 |
wait(Long timeout) | 指定等待的毫秒值 |
notify() | 唤醒一个处于等待状态的线程 |
notifyAll() | 唤醒同一个对象上所有调用wait()方法的线程,优先级高的线程优先调度 |
注意: 均是Object类的方法。都只能在同步方法或者同步代码块中使用,否则会抛出异常IllegalMonitorStateException
管程法
//线程通信,生产者和消费者 ---中间加入缓存区---->管程法
public class ThreadPC {
public static void main(String[] args) {
Buffer buffer = new Buffer();
new Producer(buffer).start();
new Customer(buffer).start();
}
}
//生产者
class Producer extends Thread{
Buffer buffer;
public Producer(Buffer buffer) {
this.buffer = buffer;
}
//生产
@Override
public void run() {
for (int i = 0; i < 100; i++) {
buffer.put(new Chicken(i));
System.out.println("生产了第-->"+i+"只鸡");
}
}
}
//消费者
class Customer extends Thread{
Buffer buffer;
public Customer(Buffer buffer) {
this.buffer = buffer;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
Chicken chicken = buffer.get();
System.out.println("消费了第-->"+chicken.id+"只鸡");
}
}
}
//产品
class Chicken{
int id;
public Chicken(int id) {
this.id = id;
}
}
//缓存区
class Buffer{
//容器.装产品
Chicken[] chickens = new Chicken[10];
//计数
int count = 0;
//生产者生产产品丢入容器
public synchronized void put(Chicken chicken){
//判断容器中是否已满
if (count == chickens.length){
//容器满了.生产者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//生产者生产.添加
chickens[count]=chicken;
count++;
//通知消费者消费
this.notifyAll();
}
//消费者消费产品
public synchronized Chicken get(){
//消费者判断容器中是否有产品
if (count == 0){
//消费者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//消费
Chicken chicken = chickens[count-1];
chickens[count-1] = null;
count--;
//通知生产者生产
this.notifyAll();
return chicken;
}
}
信号灯法
//测试信号灯方式 标志符
public class TestSignalLamp {
public static void main(String[] args) {
Exchange exchange = new Exchange();
new Producer1(exchange).start();
new Customer1(exchange).start();
}
}
//生产者
class Producer1 extends Thread{
Exchange exchange;
public Producer1(Exchange exchange) {
this.exchange = exchange;
}
//生产鸡
@Override
public void run() {
for (int i = 0; i < 100; i++) {
exchange.doChicken(new Chicken1(i));
}
}
}
//消费者
class Customer1 extends Thread{
Exchange exchange;
public Customer1(Exchange exchange) {
this.exchange = exchange;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
exchange.eatChicken();
}
}
}
//产品
class Chicken1{
int id;
public Chicken1(int id) {
this.id = id;
}
}
//标志符--通信
class Exchange{
//定义标志符
boolean flag;
Chicken1 chicken;
//生产者做鸡
public synchronized void doChicken(Chicken1 ck){
//当标志符为true时,生产线程等待
if (flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.chicken = ck;
this.flag = true;
System.out.println("生产了一只鸡"+chicken.id);
//通知消费者
this.notifyAll();
}
//消费者吃鸡
public synchronized void eatChicken(){
//当flag为false时无鸡可吃
if (!flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("吃了一只鸡==_=="+chicken.id);
chicken = null;
this.flag = false;
//通知生产生产
this.notifyAll();
}
}
线程池
提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。避免频繁创建与销毁、实现重复利用,提高效率
- 提高响应速度(减少了创建线程时间)
- 降低资源消耗(可重复使用)
- 便于管理
- corePoolSize: 核心池大小
- maximumPoolSize : 最大线程数
- keepAliveTime: 线程没有任务时最多保持多长时间会终止
public class TestPool {
public static void main(String[] args) {
//创建线程池--指定线程数
ExecutorService service = Executors.newFixedThreadPool(10);
//执行
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
//关闭链接
service.shutdown();
}
}
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"创建滴滴滴");
}
}