Java多线程-黑马阿玮

Java多线程

为什么要有多线程?

进程

进程是程序的基本执行实体

线程

线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程的实际运作单位。

简单理解:应用软件中互相独立,可以同时运行的功能

多线程的应用场景:

  1. 软件中的耗时操作

  2. 拷贝,迁移大文件

  3. 加载大量的资源文件

  4. 所有的聊天软件

  5. 所有的后台服务器

多线程的作用:提高效率

多线程的两个概念

并发:在同一时刻,有多个指令在单个CPU上交替执行

并行:在同一时刻,有多个指令在多个CPU上同时执行

多线程的实现方式

多线程的实现方式:

  1. 继承Thread类的方式进行实现

  2. 实现Runnable接口的方式进行实现

  3. 利用Callable接口和Future接口方式实现

  4. 【线程池创建】

多线程的第一种启动方式

继承Thread类的方式进行实现:

  1. 自己定义一个类继承Thread

  2. 重写run方法

  3. 创建子类的对象,并启动该线程

public class MyThread extends Thread{
     
     @Override
     public void run(){
         //书写线程要执行的代码
         for(int i = 0;i < 100;i++){
             System.out.printf(getName() + "HelloWorld");
         }
     }
 }
 
public class ThreadDemo{
     public static void main(String[] args){
         /*
         多线程的第一种启动方式
         
         1. 自己定义一个类继承Thread
        2. 重写run方法
        3. 创建子类的对象,并启动该线程
        */
         
         MyThread t1 = new MyThread();
         MyThread t2 = new MyThread();
         
         t1.setName("线程1");
         t1.setName("线程2");
         
         t1.start();
         t2.start();
     }
 }

多线程的第二种启动方式

实现Runnable接口的方式进行实现:

  1. 自己定义一个类实现Runnable接口

  2. 重写里面的run方法

  3. 创建自己的类的对象

  4. 创建一个Thread类的对象,并开启线程

public class MyRun implements Runnable{
     
     @Override
     public void run(){
         //书写线程要执行的代码
         for(int i = 0;i < 100;i++){
             //获取到当前线程的对象
             /*Thread t = Thread.currentThread();
             System.sout.println(t.getName() + "HelloWorld");*/
             System.sout.println(Thread.currentThread().getName() + "HelloWorld");
         }
     }
 }
 public class ThreadDemo{
     public static void main(String[] args){
         /*
         多线程的第二种启动方式:
         
         1. 自己定义一个类实现Runnable接口
         2. 重写里面的run方法
         3. 创建自己的类的对象
         4. 创建一个Thread类的对象,并开启线程
         */
         
         //创建MyRun的对象
         MyRun mr = new MyRun();//表示多线程要执行的任务
         
         //创建线程对象
         Thread t1 = new Thread(mr);
         Thread t2 = new Thread(mr);
         
         //给线程设置名字
         t1.setName("线程1");
         t2.setName("线程2");
         
         //开启线程
         t1.start();
         t2.start();
     }
 }

多线程的第三种启动方式

利用Callable接口和Future接口方式实现:

特点:可以获取到多线程运行的结果

  1. 创建一个类 MyCallable 实现 Callable 接口

  2. 重写 call 【是有返回值的,表示多线程运行的结果】

  3. 创建 MyCallable 的对象【表示多线程要执行的任务】

  4. 创建 FutureTask 的对象【作用管理多线程运行的结果】

  5. 创建 Thread 类的对象,并启动【表示线程】

 public class MyCallable iplements Callable<Integer> {
     @Override
     public Integer call() throws Excepion{
         //求1 ~ 100之间的和
         int sum = 0;
         for(int i = 1;i <= 100;i++){
             sum = sum + i;
         }
         return sum;
     }
 }
 
public class ThreadDemo{
     public static void main(String[] args){
         
         /*
         多线程的第三种启动方式
 ​
         利用Callable接口和Future接口方式实现:
         特点:可以获取到多线程运行的结果
     
         1. 创建一个类 MyCallable 实现 Callable 接口
         2. 重写 call 【是有返回值的,表示多线程运行的结果】
         3. 创建 MyCallable 的对象【表示多线程要执行的任务】
         4. 创建 FutureTask 的对象【作用管理多线程运行的结果】
         5. 创建 Thread 类的对象,并启动【表示线程】
         */
         
         //创建 MyCallable 的对象【表示多线程要执行的任务】
         MyCallable mc = new MyCallable();
         //创建 FutureTask 的对象【作用管理多线程的运行结果】
         FutureTask<Integer> ft = new FutureTask<>(mc);
         //创建线程的对象
         Thread t1 = new Thread(ft);
         //启动线程
         t1.start();
         
         //获取多线程运行的结果
         Integer result = ft.get();
         System.out.println(result);
         
     }
 }
     输出:5050

多线程三种实现方式对比

实现方式优点缺点
继承 Thread 类编程比较简单,可以直接使用 Thread 类中的方法可扩展性较差,不能在继承其他的类
实现 Runnable 接口扩展性强,实现该接口的同时还能继承其他的类编程相对复杂,不能直接使用 Thread 类中的方法
实现 Callable 接口扩展性强,实现该接口的同时还能继承其他的类编程相对复杂,不能直接使用 Thread 类中的方法

常见的成员方法

方法名称说明
String getName()返回此线程的名称
void setName(String name)设置线程的名字【构造方法也可以设置名字】
static Thread currentThread()获取当前线程的对象
static void sleep(long time)让线程休眠指定的时间,单位为毫秒
setPriority(int new Priority)设置线程的优先级【默认为5,1最低,10最高】
final int getPriority()获取线程的优先级
final void setDaemon(boolean on)设置为守护线程
public static void yield()出让线程/礼让线程
public void join()插入线程/插队线程

演示

public class MyThread extends Thread{
     public MyThread(){
     }
     public MyThread(){
         super(name);
     }
     
     @Override
     public void run(){
         for(int i =0;i < 100;i++){
             System.out.println(getName() + "@" + i);
         }
     }
 }
 
public class ThreadDemo{
     public static void main(String[] args){
         /*
         1、String getName()  返回此线程的名称
         2、void setName(String name) 设置线程的名字(构造方法也可以设置名称)
         细节:
             1.如果我们没有给线程设置名字,线程也是有默认名字的
                 格式:Thread-X(X序号,从0开始)
             2.如果我们要给线程设置名字,可以用set方法进行设置,也可以构造方法进行设置
         
         3、static Thead currentThread() 获取当前线程的对象
         细节:
             当JVM虚拟机启动之后,会自动的启动多条线程
             其中有一条线程叫做main线程
             它的作用就是去调用main方法,并执行里面的代码
             
         4、static void sleep(long time) 让线程休眠指定的时间,单位为毫秒
         细节:
             1.哪条线程执行到这个方法,那么哪条线程就会在这停留对应的时间
             2.方法的参数:就表示睡眠的时间,单位为毫秒
             3.当时间到了之后,线程就会自动醒来,继续执行下面的其他代码
         */
         /*
         //1.创建线程的对象
         MyThread t1 = new MyThread("飞机");
         MyThread t2 = new MyThread("坦克");
         
         //2.开启线程
         t1.start();
         t2.start();
         */
         /*
         //哪条线程执行到这个方法,此时获取的就是哪条线程的对象
         Thread t = Thread.currentThread();
         String name = t.getName();
         System.out.println(name);//main
         */
         /*
         System.out.println("睡眠前");
         Thread.sleep(5000);
         System.out.println("睡眠后");
         */
     }
 }

线程的调度

非抢占式调度 -

抢占式调度 - 随机性 【Java中】

该线程优先级越高,抢占CPU执行权的机会越大

public class MyRunnable implements Runnable{
    
    @Override
    public void run(){
        for(int i = 1;i <= 100;i++){
            System.out.println(Thread.currentThread().getName + "---" + i);
        }
    }
}
public class ThreadDemo{
    public static void main(String[] args){
        /*
        5、setPriority(int new Priority)		设置线程的优先级
        6、final int getPrioroty()			获取线程的优先级
        
		*/
        
        //创建线程要执行的参数对象
        MyRunnable mr = new MyRunnable();
        //创建线程对象
        Thread t1 = new Thread(mr,"飞机");
        Thread t2 = new Thread(mr,"坦克");
        /*
        System.out.println(t1.getPriority());//5
        System.out.println(t1.getPriority());//5
        */
        t1.setPriority(1);
        t2.setPriority(10);
        
        t1.start();
        t2.start();
    }
}

守护线程

public class MyThread1 extends Thread{
    @Override
    public void run(){
        for(int i = 1;i <= 10;i++){
            System.out.println(getName() + "@" + i);
        }
    }
}
public class MyThread2 extends Thread{
    @Override
    public void run(){
        for(int i = 1;i <= 100;i++){
            System.out.println(getName() + "@" + i);
        }
    }
}
public class ThreadDemo{
    public static void main(String[] args){
        /*
        7、final void setDaemon(boolean on)	设置为守护线程
        细节:
        	当其他的非守护线程执行完毕之后,守护线程会陆续结束
        通俗易懂:
        	当女神线程结束之后,那么备胎线程也没有存在的必要的,会陆陆续续结束备胎线程
        */
        MyThread1 t1 = new MyThread1();
        MyThread2 t2 = new MyThread2();
        
        t1.setName("女神");
        t2.setName("备胎");
        
        //把第二个线程设置为守护线程【备胎线程】
        t2.setDaemon(true);
        
        t1.start();
        t2.start();
    }
}

出让线程/礼让线程

public class MyThread extends Thread{
    @Override
    public void run(){
        for(int i = 1; i<= 100;i++){
            System.out,println(getName() + "@" +i);
            //表示出让当前CPU的执行权
            Thread.yield();
        }
    }
}
public class ThreadDemo{
    public static void main(String[] args){
        /*
        8、public static void yield()	出让线程/礼让线程
        */
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        
        t1.setName("飞机");
        t2.setName("坦克");
        
        t1.start();
        t2.start();
    }
}

插入线程/插队线程

当插入线程之后,这个插入线程执行完才会释放CPU执行权

public class MyThread extends Thread{
    @Override
    public void run(){
        for(int i = 1;i <= 100;i++){
            System.out.println(getName() + "@" + i);
        }
    }
}
public class ThreadDemo{
    public static void main(String[] args){
        /*
        9、public final void join()	插入线程/插队线程
        */
        
        MyThread t = new MyThread();
        t.setName("土豆");
        t.start();
        
        //表示把t这个线程,插入到当前线程之前
        //t:土豆
        //当前线程:main线程
        t.join();
      	
        //执行在main线程当中的
        for(int i = 0;i < 10;i++){
            System.out.println("main线程" + i);
        }
    }
}

线程的生命周期

线程的生活周期中,它有五种状态:

  1. 新建(New)

  2. 就绪(Runnable)

  3. 运行(Running)

  4. 阻塞(Blocked)

  5. 死亡(Dead)

问:sleep方法会让线程睡眠,睡眠时间到了以后,立马就会执行下面的代码吗?

不会,线程睡眠时间到了之后会重新变为 就绪 状态,要去抢夺CPU的执行权才能执行代码。

线程安全的问题

public class MyThread extends Thread{
    //表示这个类所有的对象,都共享ticket数据
    static int ticket = 0;//0~99
    
    @Override
    public void run(){
        while(true){
            if(ticket < 100){
                try{
                    Thread.sleep(100);
                }catch(InterruptedException e){
                    e.printSrackTrace();
                }
                
                ticket++;
                System.out.println(getName() + "正在卖第" +ticket + "张票!!");
            }else{
                break;
            }
        }
    }
}
public class ThreadDemo{
    public static void main(String[] args){
        /*
        需求:
        	某电影目前正在上映国产大片,共有100张票,而他有三个窗口卖票,请设计一个程序模拟电影院卖票
        */
        
        //创建线程对象
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        MyThread t3 = new MyThread();
        
        //起名字
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        
        //开启线程
        t1.start();
        t2.start();
        t3.start();
    }
}

买票引发的安全问题

  1. 相同的票出现多次

  2. 出现了超出范围的票

同步代码块

把操作共享数据的代码锁起来

格式:

synchronized(锁){
    操作共享数据的代码
}
  • 特点1:锁默认打开,有一个线程进去了,锁自动关闭。

  • 特点2:里面的代码全部执行完毕,线程出来,锁自动打开。

public class MyThread extends Thread{
    //表示这个类所有的对象,都共享ticket数据
    static int ticket = 0;//0~99
    
    //锁对象,一定要是唯一的
    static Object obj = new Object();
    
    @Override
    public void run(){
        while(true){
           //同步代码块
           synchronized(obj){
                if(ticket < 100){
                try{
                    Thread.sleep(100);
                }catch(InterruptedException e){
                    e.printSrackTrace();
                }
                
                ticket++;
                System.out.println(getName() + "正在卖第" +ticket + "张票!!");
            }else{
                break;
            }
           }
        }
    }
}
同步代码块的两个小细节
  1. synchronized 无法写在循环的外面

  2. synchronized(obj) 其中obj 【锁对象】要是唯一的,一般为当前类的字节码文件对象 类名.class

同步方法

就是把synchronized 关键字加到方法上

格式

修饰符 synchronized 返回值类型 方法名(方法参数){...}

特点:

  1. 同步方法是锁住方法里面的所有代码

  2. 锁对象不能自己指定,是Java已经规定好的

    1. 非静态:this

    2. 静态:当前类的字节码文件对象

示例:

public class MyRunnable implements Runnable{
    static int ticket = 0;
    
    @Override
    public void run(){
        //1.循环
        while(true){
            if(method()) break;
        }
    }
    
    //this
    private synchronized boolean method(){
        //3.判断共享数据是否到了末尾,如果到了末尾
        if(ticket == 100){
            return true;
        }else{
            //4.判断共享数据是否到了末尾,如果到了末尾
            try{
                Thread.sleep(10);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            ticket++;
            System.out.println(Thread.currentThread().getName + "在卖第" + ticket +张票!!!);
        }
    }
}
public class ThreadDemo{
    public static void main(String[] args){
        /*
        需求:
        	某电影目前正在上映国产大片,共有100张票,而他有三个窗口卖票,请设计一个程序模拟电影院卖票
        	利用同步方法完成
        	技巧:同步代码块
        */
        MyRunnable mr = new MyRunnable();
        Thread t1 = new Thread(mr);
        Thread t2 = new Thread(mr);
        Thread t3 = new Thread(mr);
        
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        
        t1.start();
        t2.start();
        t3.start();
    }
}

延申:

String buffer和String builder区别

  1. StringBuffer 与 StringBuilder 中的方法和功能完全是等价的 。

  2. 只是StringBuffer 中的方法大都采用了 synchronized 关键字进行修饰,因此是线程安全的,而 StringBuilder 没有这个修饰,可以被认为是线程不安全的。

  3. 在单线程程序下,StringBuilder效率更快,因为它不需要加锁,不具备多线程安全而StringBuffer 则每次都需要判断锁,效率相对更低

lock锁

虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没直接看到在哪里上的锁,在哪里释放锁,为了更清晰的表达如何加锁和释放锁,JDK5 以后提供了一个新的锁对象Lock

Lock实现提供比使用 synchronized 方法和语句可以获得更广泛的锁定操作

Lock中提供了获得锁和释放锁的方法

void lock();//获得锁,手动上锁
void unlock();//释放锁,手动解锁

Lock 是接口不能直接实例化,这里采用它的实现类 ReentrantLock 来实例化

ReentrantLock 的构造方法

ReentrantLock():创建一个 ReentrantLock 的实例

public class MyRunnable implements Runnable{
    static int ticket = 0;
    
    static Lock lock = new ReentrantLock();
    
    @Override
    public void run(){
     //1.循环
        while(true){
            //2.同步代码块
            //synchronized(MyThread.class){
            lock.lock();
            try{
                //3.判断
                if(ticket == 100){
                    break;
                    //4.判断
                }else{
                    Thread.sleep(10);
                    ticket++;
                     System.out.println(getName + "在卖第" + ticket +张票!!!);
                }
                //}
            }catch(InterruptedException e){
                e.printSrackTrace();
            }finally{
                lock.unlock();
            }
            }
        }
    }
    
}

public class ThreadDemo{
    public static void main(String[] args){
        /*
        需求:
        	某电影目前正在上映国产大片,共有100张票,而他有三个窗口卖票,请设计一个程序模拟电影院卖票
        */   
	//创建线程对象
    MyThread t1 = new MyThread();
    MyThread t2 = new MyThread();
    MyThread t3 = new MyThread();
    
    //起名字
    t1.setName("窗口1");
    t2.setName("窗口2");
    t3.setName("窗口3");
    
    //开启线程
    t1.start();
    t2.start();
    t3.start();
	}
}

死锁

以后写锁的时候,千万不能让锁嵌套起来

生产者和消费者

生产者和消费者【等待唤醒机制】

生产者消费者模式是一个十分经典的多线程协作的模式

  • 生产者:生产数据

  • 消费者:消费数据

消费者等待

  1. 判断桌子上是否有食物

  2. 如果没有就等待

  3. 如果有就开吃

  4. 吃完之后,唤醒厨师继续做

生产者等待

  1. 判断桌子上是否有食物

  2. 有:等待

  3. 没有:制作食物

  4. 把食物放在桌子上

  5. 叫醒等待的消费者开吃

生产者和消费者【常见方法】

方法名称说明
void wait()当前线程等待,直到被其他线程唤醒
void notify()随即唤醒单个线程
void notifyAll()唤醒所有线程

消费者代码实现

生产者

public class Cook extends Thread{
    @Override
    public void run(){
        /*
        1.循环
        2.同步代码块
        3.判断共享数据是否到了末尾【到了末尾】
        4.判断共享数据是否到了末尾【没有到末尾,执行核心逻辑】
        */
        
        while(true){
            synchronized(Desk.lock){
                if(Desk.count == 0){
                    System.out.println("不需要再做面条啦!!!");
                    break;
                }else{
                    //判断桌子上有没有食物
                    if(Desk.foodFlag == 1){
                        //如果有就等待
                        try{
                            Desk.lock.wait();
                        }catch(InterruptedException e){
               				e.printSrackTrace();
            		}
                    }else{
                        //如果没有,就制作食物
                        System.out.println("厨师做了一碗面条");
                        //修改桌子上的状态
                        Desk.foodFlag = 1;
                        //叫醒等待的消费者开吃
                        Desk.lock.notifyAll();
                    }
                }
            }
        }
    }
}

消费者

public class Foodie extends Thread{
    @Override
    public void run(){
        /*
        1.循环
        2.同步代码块
        3.判断共享数据是否到了末尾【到了末尾】
        4.判断共享数据是否到了末尾【没有到末尾,执行核心逻辑】
        */
        while(true){
            synchronized(Desk.lock){
                if(Desk.count == 0){
                    break;
                }else{
                    //先判断桌子上是否有面条
                    if(foodFlag == 0){
                         //如果没有,就等待
                        try{
                            Desk.lock.wait();//让当前线程跟锁进行绑定
                        }catch(InterruptedException e){
               				e.printSrackTrace();
            		}
                    }else{
                    //把吃的总数 -1
                        Desk.count--;
                    //如果有,就开吃
                        System.out.println("吃货还在吃面条,还能再吃" + Desk.count + "碗!!");
                    //吃完之后,唤醒厨师继续做
                    	Desk.lock.notifyAll();
                    //修改桌子的状态
                        Desk.foodFlag = 0;
                    }
                   
                }
            }
        }
    }
}

桌子【中间桥梁】

public class Desk{
	/*
	作用:
	控制生产者和消费者的执行
	*/
    //是否有面条 0:没有面条 1:有面条
    public static int foodFlag = 0;
	
    //总个数
    public static int count = 10;
    
    //锁对象
    public static Object lock = new Object();
}

测试

public class ThreadDemo{
    public static void main(String[] args){
        /*
        需求:
        	实现生产者和消费者【等待唤醒机制】的代码
        	实现线程轮流交替执行的效果
        */
        //创建线程的对象
        Cook c = new Cook();
        Foodie f = new Foodie();
        
        //给线程设置名字
        c.setName("厨师");
        f.setName("吃货");
        
        //开启线程
        c.start();
        f.start();
    }
}

生产者和消费者【阻塞队列方式实现】

  • PUT数据时:放不进去,会等着,也叫做阻塞。

  • take数据时:取出来第一个数据,取不到会等着,也叫做阻塞。

阻塞队列的继承结构
  • 接口

    • Iterable

    • Collection

    • Queue

    • BlockingQueue

  • 实现类

    • ArrayBlockingQueue:底层是数组,有界

    • LinkedBlockingQueue:底层是链表,无界但不是真正的无界,最大为int的最大值。

生产者

public class Cook extends Thread{
    
    ArrayBlockingQueue<String> queue;
    
    public Cook(ArrayBlockingQueue<String> queue){
        this.queue = queue;
    }
    
    @Override
    public void run(){
       while(true){
           //不断的把面条放到阻塞队列中
           try{
               queue.put("面条");
               System.out.println("厨师放了一碗面条");
           }catch(InterruptedException e){
               	e.printSrackTrace();
           }
       }
    }
}

消费者

public class Foodie extends Thread{
    
    ArrayBlockingQueue<String> queue;
    
    public Foodie(ArrayBlockingQueue<String> queue){
        this.queue = queue;
    }
    
    @Override
    public void run(){
      while(true){
          //不断从阻塞队列中获取面条
          try{
              String food = queue.take();
              System.out.println(food);
          }catch(InterruptedException e){
               	e.printSrackTrace();
           }
      }
    }
}

测试

public class ThreadDemo{
    public static void main(String[] args){
        /*
        需求:利用阻塞队列完成生产者和消费者【等待唤醒机制】的代码
        细节:
        	生产者和消费者必须使用同一个阻塞队列
        */
        
        //1.创建阻塞队列的对象
        ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);
        //创建线程的对象
        Cook c = new Cook(queue);
        Foodie f = new Foodie(queue); 
        
        //开启线程
        c.start();
        f.start();
    }
}

多线程的六种状态

当一个线程抢到了CPU的执行权的时候,那么虚拟机就会把当前线程就给虚拟机去执行,所以为什么Java没有定义线程的运行

在Java当中只有以下的六种状态

线程池

以前多线程的弊端:

  1. 用到线程的时候就创建

  2. 用完之后就消失

线程池 主要核心原理

  1. 创建一个池子,池子中是空的

  2. 提交任务时,池子会创建新的线程对象,任务执行完毕,线程归还池子,下回再次提交任务时,不需要创建新的多线程,直接复用已有的线程即可

  3. 但是如果提交任务时,池子中没有空闲线程,也无法创建新的线程,任务就会排队等待

线程池 代码实现

Executors :线程池的工具类通过调用方法返回不同类型的线程池对象。

方法名称说明
public static ExecutorService newCachedThreadPool()创建一个没有上限的线程池【最大容量为int 最大值】
public static ExecutorService newFixedThreadPool(int nThreads)创建有上线的线程池

代码演示

public class MyRunnable implements Runnable{
     @Override
     public void run(){
         
         for(int i = 1; i<= 100;i++){
             System.out.println(Thread.currentThead().getName() + "---" + i);
         }
         
     }
 }

public class MyTheadPoolDemo{
     /*
       public static ExecutorService newCachedThreadPool()创建一个没有上限的线程池【最大容量为int 最大值】      public static ExecutorService newFixedThreadPool(int nThreads)创建有上线的线程池
     */
     
     //1.获取线程池对象
     ExecutorService pool1 = Executors.newCachedThreadPool();
     ExecutorService pool2 = Executors.newFixedThreadPool(3);//线程池的最大线程数为3
     
     //提交任务
     pool1.submit(new MyRunnable);
     pool1.submit(new MyRunnable);
 }

自定义线程池

自定义线程池 【任务拒绝策略】

任务拒绝策略说明
ThreadPoolExecutor.AbortPolicy默认策略:丢弃任务并抛出RejectedExecutionException异常
ThreadPoolExecutor.DiscardPolicy丢弃任务,但是不抛出异常,这是不推荐的做法
ThreadPoolExecutor.DiscardOldestPolicy抛弃队列中等待时间最久的任务,然后把当前任务加入队列中
ThreadPoolExecutor.CallerRunsPoolicy调用任务的run()方法绕过线程池直接执行

public class MyThreadPoolDemo{
     public static void main(String[] args){
         /*
         ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor
         (核心线程数量,最大线程数量,空闲线程最大存活时间,任务队列,创建线程工厂,任务的拒绝策略)
         
         参数一:核心线程数量          不能小于0
         参数二:最大线程数            不能小于等于0,最大数量》=核心线程数量
         参数三:空闲线程最大存活时间    不能小于0
         参数四:时间单位              用TimeUnit指定
         参数五:任务队列              不能为null
         参数六:创建线程工厂           不能为null
         参数七:任务的拒绝策略         不能为null
         */
         ThreadPoolExecutor pool = new ThreadPoolExecutor(
         3,//核心线程数量
         6,//最大线程数
         60,//空闲线程最大存活时间
         TimeUnit.SECONDS,//时间单位
         new ArrayBlockingQueue<>(3),//任务队列
         Executorys.defaultThreadFactory(),//创建线程工厂
         new ThreadPoolExecutor.AbortPolicy()//任务拒绝策略
         );
         
     }
 }

自定义线程池小结

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叫一只啦啦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值