多线程..

news2024/10/6 14:29:21

线程定义:线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中实际运作单位。简单来说,应用软件中相互独立,可以同时运作的功能。

多线程作用:有了多线程,我们就可以让程序同时做多件事情。

应用场景:只要你想让多个事件同时运行就需要用到多线程。

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

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

多线程的实现方式

1.继承Thread类的方式进行执行

步骤:

自己定义一个类继承Thread

重写run方法

创建子类的对象,并启动线程。

public class MyThread extends Thread{
	@Override
	public void run() {
		for(int i=0;i<10;i++) {
			System.out.println("Hello");
		}
	}

}
public class test {
    public static void main(String [] args)  {
    	//创建子类对象,开启线程
    	MyThread mt=new MyThread();
    	mt.start();
	 }
}

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

步骤:

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

重写里面的run方法

创建自己类的对象

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

public class MyThread implements Runnable{
	@Override
	public void run() {
		for(int i=0;i<10;i++) {
			System.out.println("world");
		}
	}

}
public class test {
    public static void main(String [] args)  {
    	//创建自己类的对象
    	MyThread mt=new MyThread();
    	//创建Thread对象,并开启线程
    	Thread t=new Thread(mt);
    	t.start();
	 }
}

 

若想看看两个线程的相互执行,获取线程的名字:

public class MyThread implements Runnable{
	//在此获取线程的名字
	@Override
	public void run() {
		for(int i=0;i<10;i++) {
		Thread t=Thread.currentThread();//获取当前线程对象
		System.out.println(t.getName()+":world");
		}
	}

}
public class test {
    public static void main(String [] args)  {
    	//创建自己类的对象
    	MyThread mt=new MyThread();
    	//创建Thread对象,并开启线程
    	Thread t1=new Thread(mt);
    	Thread t2=new Thread(mt);
    	//给线程设置名字
    	t1.setName("线程1");
    	t2.setName("线程2");
    	t1.start();
    	t2.start();
	 }
}

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

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

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

2)重写call方法(是有返回值的,表示多线程运行的结果);

3)创建MyCallable的对象(表示多线程要执行的任务);

4)创建FutureTask的对象(作用管理多线程的运行结果);

5)创建Thread类的对象,并启动(表示线程)。

public class MyCallable implements Callable<Integer>{
    //计算1~10的和
	@Override
	public Integer call() throws Exception {
		int sum=0;
		for(int i=0;i<=10;i++) {
			sum+=i;
		}
		return sum;
	}

}
public class test {
    public static void main(String [] args) throws InterruptedException, ExecutionException  {
    	MyCallable mc=new MyCallable();
    	FutureTask<Integer> ft=new FutureTask<>(mc);//管理多线程运行结果
    	Thread t=new Thread(ft);
    	t.start();//开启线程
    	//获取返回值
         Integer sum=ft.get();
         System.out.println(sum);
	 }
}

多线程的成员方法

获取与设置线程的名字

注:若我们未给线程设置名字,线程也有默认的名字,格式:Thread-X(X为序号,从0开始)。

若我们要给线程设置名字,可以用set方法,也可以用构造方法(调用父类的构造方法)设置。

1)用set进行设置。

public class MyThread extends Thread{
	@Override
	public void run() {
		for(int i=0;i<10;i++) {
			//获取线程名字
			System.out.println(getName()+":"+i);
		}
	}

}

public class test {
    public static void main(String [] args)  {
    	MyThread t1=new MyThread();
    	MyThread t2=new MyThread();
    	//设置线程名字,用set方法设置
    	t1.setName("线程1");
    	t2.setName("线程2");
    	t1.start();
    	t2.start();
	 }
}

线程之间交替运行。 

2)用构造方法进行设置

public class MyThread extends Thread{
	public MyThread() {//调用父类的构造方法
		
	}
	public MyThread(String name) {
		super(name);
	}
	@Override
	public void run() {
		for(int i=0;i<10;i++) {
			System.out.println(getName()+":"+i);
		}
	}

}
public class test {
    public static void main(String [] args)  {
    	MyThread t1=new MyThread("飞机");
    	MyThread t2=new MyThread("鼠标");
    	t1.start();
    	t2.start();
	 }
}

线程休眠

static void sleep(long time)——让线程休眠指定时间,单位毫秒。

注:哪条线程执行到这个方法,那么哪条线程就会在这停留对应的时间。当时间到了之后,线程会自动醒来,执行下面的代码。

public class MyThread extends Thread{
	public MyThread() {//调用父类的构造方法
		
	}
	public MyThread(String name) {
		super(name);
	}
	@Override
	public void run() {
		for(int i=0;i<10;i++) {
			try {
				Thread.sleep(1000);//每个一秒打印一个数据
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(getName()+":"+i);
		}
	}

}
public class test {
    public static void main(String [] args)  {
    	MyThread t1=new MyThread("飞机");
    	MyThread t2=new MyThread("鼠标");
    	t1.start();
    	t2.start();
	 }
}

线程的优先级

在java中使用抢占式调度,其特点为随机性。优先级为1~10,默认优先级为5,优先级越高,抢到CPU的概率越大,但并不是百分之一百抢到CPU。

public class MyThread extends Thread{
	@Override
	public void run() {
		for(int i=0;i<7;i++) {
			System.out.println(getName()+":"+i);
		}
	}
}
public class test {
    public static void main(String [] args)  {
    	MyThread t1=new MyThread();
    	MyThread t2=new MyThread();
    	//设置线程名字
    	t1.setName("键盘");
    	t2.setName("鼠标");
    	//设置线程的优先级
    	t1.setPriority(1);
    	t2.setPriority(10);
    	t1.start();
    	t2.start();
	 }
}

鼠标优先级大,鼠标先执行完毕。

守护线程

当其他非守护线程结束后,守护线程也会陆续结束(一般不会执行完毕)。

public class MyThread1 extends Thread{
	@Override
	public void run() {
		for(int i=0;i<8;i++) {
			System.out.println(getName()+":"+i);
		}
	}
}
public class MyThread2 extends Thread{
	@Override
	public void run() {
		for(int i=0;i<100;i++) {
			System.out.println(getName()+":"+i);
		}
	}
}
public class test {
    public static void main(String [] args)  {
    	MyThread1 t1=new MyThread1();
    	MyThread2 t2=new MyThread2();
    	//设置线程名字
    	t1.setName("线程");
    	t2.setName("备份");
    	//将t2设置为守护线程
    	t2.setDaemon(true);
    	t1.start();
    	t2.start();
	 }
}

礼让线程

礼让线程也叫出让线程,作用:尽可能使结果均匀一点。

public class MyThread extends Thread{
	@Override
	public void run() {
		for(int i=0;i<8;i++) {
			System.out.println(getName()+":"+i);
			Thread.yield();//出让线程
		}
	}
}
public class test {
    public static void main(String [] args)  {
    	MyThread t1=new MyThread();
    	MyThread t2=new MyThread();
    	//设置线程名字
    	t1.setName("线程1");
    	t2.setName("线程2");
    	
    	t1.start();
    	t2.start();
	 }
}

插入线程

public class MyThread extends Thread{
	@Override
	public void run() {
		for(int i=0;i<100;i++) {
			System.out.println(getName()+":"+i);
		}
	}
}
public class test {
    public static void main(String [] args) throws InterruptedException  {
    	MyThread t1=new MyThread();	
    	t1.setName("土豆");
    	t1.start();
    	t1.join();//插入线程,将土豆线程插入到main线程之前
    	for(int i=0;i<10;i++) {
    		System.out.println("main线程"+i);
    	}
	 }
}

线程的生命周期

同步代码块

把操作共享的代码锁起来。

锁对象一定要求是唯一的。

 利用同步代码块可解决线程安全问题。若没有锁,可能会出现数据重复,数据超出要求的范围等等问题。

练习

某电影院目前正在上映国产大片,共有100张票,而它有3个窗口卖票,请设计一个程序模拟该电影院卖票。

public class MyThread extends Thread{
	//设置一个静态数据,表示这个类所有对象可以共享
	  static int ticket=0;//票数
	  static Object obj=new Object();//锁对象一定要是唯一的
	@Override
	public void run() {
		while(true) {
			synchronized(obj) {
			if(ticket<100) {
				try {
					Thread.sleep(100);//数据慢慢的输出
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				ticket++;
				System.out.println(getName()+"今天卖出第"+ticket+"票");
			}else {
				break;
			}
			}
		}
	}
}
public class test {
    public static void main(String [] args)  {
    	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();
	 }
}

同步方法

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

同步方法是用同步代码块提取方法,改编而来的。

练习

某电影院目前正在上映国产大片,共有100张票,而它有3个窗口卖票,请设计一个程序模拟该电影院卖票。(使用同步方法完成,技巧:先构建好同步代码块,在进行变换)

public class MyThread implements Runnable{//使用第二种方法
    int ticket=0;//使用第二种方法创建对象,不用设置这个为静态的
    @Override
    public void run() {
        while(true) {       
                if (mehod()) break;         
        }

    }
    private synchronized boolean mehod() {//同步方法
        if(ticket==100) {
            return true;
        }else {
            try {
                Thread.sleep(100);//若想要看到多个线程交织进行,可采用sleep让线程睡一会
            } catch (final InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            ticket++;
            System.out.println(Thread.currentThread().getName()+"今天卖了第"+ticket+"张票");
        }
        return false;
    }


}
public class test1 {
    public static void main(String[] args) {
        MyThread mt=new MyThread();
        Thread t1=new Thread(mt);
        Thread t2=new Thread(mt);
        Thread t3=new Thread(mt);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}

Lock锁


 练习

某电影院目前正在上映国产大片,共有100张票,而它有3个窗口卖票,请设计一个程序模拟该电影院卖票。(利用Lock锁进行)

在Lock锁当中利用try-catch-finall来进行开锁关锁。,将while循环中的主体程序写完之后,从获得锁开始后利用快捷方法生成try-catch-finall,finally中写释放锁。

public class MyThread extends Thread{
    //设置一个静态数据,表示这个类所有对象可以共享
    static int ticket=0;
    Lock lock=new ReentrantLock();//创建一个锁对象
    @Override
    public void run() {
        while(true) {
          //  synchronized (MyThread.class) {
            lock.lock();//获得锁
            try {
                if (ticket < 100) {
                        Thread.sleep(100);//数据慢慢的输出
                    ticket++;
                    System.out.println(getName() + "今天卖出第" + ticket + "票");
                } else {
                    break;
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();//释放锁
            }
            // }
        }
    }
}
public class test1 {
    public static void main(String[] args) {
        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:基本方法 

 有:生产者、消费者、控制生产者和消费者的代码

先写中间:

public class Desk {//中间变量
    //作用:控制消费者和生产者的代码
    //定义桌子状态,0无面条,1有面条
    public static int state=0;
    //定义吃货最大能吃多少,总个数
    public static int count=10;
    //定义锁对象
    public static Object lock=new Object();
}

消费者:

public class Eat extends Thread{//消费者
    //循环
    //同步代码块(同步方法,锁方法均可)
    //判断共享数据是否到末尾(先写到了末尾,再写未到末尾)
    @Override
    public void run(){
        while(true){
            synchronized (Desk.lock){//锁对象
                //判断共享数据是否到末尾
                if(Desk.count==0){
                    break;
                }else{
                    //先判断桌子上物品状态
                    if(Desk.state==0){
                        //如果没有消费者等待
                        try {
                            Desk.lock.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }else{
                        //如果有
                        Desk.count--;
                        System.out.println("这个人还能再吃"+Desk.count+"碗饭");
                        //吃完唤醒厨师继续做
                        Desk.lock.notifyAll();
                        //修改桌子状态
                        Desk.state=0;
                    }

                }
            }
        }
    }
}

生产者:

public class Cook extends Thread{//生产者
    @Override
    public void run(){
        while(true){
            synchronized (Desk.lock){
                if(Desk.count==0){
                    break;
                }else{
                    //判断桌子状态
                    if(Desk.state==1){
                        //如果有,就等待
                        try {
                            Desk.lock.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }else{
                        //如果没有
                        System.out.println("厨师做了一碗面");
                        //修改桌子状态
                        Desk.state=1;
                        //唤醒消费者
                        Desk.lock.notifyAll();
                    }
                }
            }
        }
    }
}

测试类:

public class test1 {
    public static void main(String[] args) {
        Cook c=new Cook();
        Eat e=new Eat();
        //设置名字
        c.setName("厨师:");
        e.setName("吃货");
        //开启线程
        c.start();
        e.start();
    }
    }

实现方法2:阻塞队列方法实现

 阻塞队列的接口和实现类:

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) {
                throw new RuntimeException(e);
            }
        }
    }
}
public class Eat extends Thread{//消费者
    ArrayBlockingQueue<String> queue;

    public Eat(ArrayBlockingQueue<String> queue) {
        this.queue=queue;
    }

    @Override
    public void run(){
        while(true){
            try {
                String food=queue.take();
                System.out.println(food);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }


        }
    }
}
public class test1 {
    public static void main(String[] args) {
      //创建阻塞队列
        ArrayBlockingQueue<String> queue=new ArrayBlockingQueue<>(10);//定义阻塞队列中的队列长度
        Cook c=new Cook(queue);
        Eat e=new Eat(queue);
        c.setName("厨师");
        e.setName("吃货");
        c.start();
        e.start();
    }
    }

线程的六种状态

综合练习

练习1:抢红包

(因为获取Double类型的随机数只能在JDK17中,抢红包实际抢到的是小数,在此题下理想化,认为是整数)
抢红包也用到了多线程。假设: 100块,分成了3个包,现在有5个人去抢。其中,红包是共享数据。5个人是5条线程。
打印结果如下:
XXX抢到了XXX元
XXX抢到了XXX元
XXX抢到了XXX元
XXX没抢到
XXX没抢到

package test1;
import java.util.Random;
public class MyThread extends  Thread{
    //定义静态变量
    static  int money=100;//总金额
    static int count=3;//红包个数
    static final int MIN=1;//抢到的金额的最小值
    @Override
    public void run() {
        synchronized (MyThread.class) {
            //判断金额
            if (money == 0) {
                System.out.println(getName() + "没有抢到红包");
            } else {
                //判断红包个数
                int prize = 0;//中奖金额
                if (count == 1) {
                    //只剩一个红包,中奖金额就是余额
                    prize = money;
                } else {
                    //进行随机数,获取红包金额
                    Random r = new Random();
                    int bound = money - (count - 1) * MIN;
                    prize = r.nextInt(bound);
                    if (prize < MIN) {
                        prize = MIN;
                    }
                }
                money = money - prize;
                count--;
                System.out.println(getName() + "抢到了" + prize + "元");
            }
        }
    }
}
public class test1 {
    public static void main(String[] args) {
        MyThread t1=new MyThread();
        MyThread t2=new MyThread();
        MyThread t3=new MyThread();
        MyThread t4=new MyThread();
        MyThread t5=new MyThread();
        t1.setName("张三");
        t2.setName("李四");
        t3.setName("王五");
        t4.setName("赵六");
        t5.setName("导航");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
    }
    }

练习2:抽奖池抽奖

有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为{10,5,20,50,100,200,500,800,2,80,300,700};
创建两个抽奖箱(线程)设置线程名称分别为“ 抽奖箱1”,‘ '抽奖箱2”随机从抽奖池中获取奖项元素并打印在控制台上格式如下:
每次抽出一个奖项就打印一个(随机)
抽奖箱1又产生了一个10元大奖
抽奖箱1又产生了一个100元大奖
抽奖箱2又产生了一个700元大奖
分析:可用集合和数组进行,但数组去重比较复杂,利用集合完成。

public class MyThread extends  Thread {
    ArrayList<Integer> list;//静态变量

    //可以利用构造方法
    public MyThread(ArrayList<Integer> list) {
        this.list = list;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (MyThread.class) {
                if (list.size() == 0) {
                    break;
                } else {
                    Collections.shuffle(list);//打乱list数据
                    int prize = list.remove(0);
                    System.out.println(getName() + "又产生了一个" + prize + "大奖");
                }
            }
            try {
                Thread.sleep(100);//目的是可以让两个线程交替进行显示
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

        }
    }
}
public class test1 {
    public static void main(String[] args) {
        ArrayList<Integer> list=new ArrayList<>();
        Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
        MyThread t1=new MyThread(list);
        MyThread t2=new MyThread(list);
        t1.setName("抽奖箱1");
        t2.setName("抽奖箱2");
        t1.start();
        t2.start();
    }
    }

练习3:多线程统计并求最大值

在上一题基础上继续完成如下需求:
每次抽的过程中,不打印,抽完时一次性打印(随机),在此次抽奖过程中,抽奖箱1总共产生了6个奖项。
分别为: 10,20,100,500,2,300最高奖项为300元,总计额为932元在此次抽奖过程中,抽奖箱2总共产生了6个奖项。
分别为: 5, 50,200,800,80,700最高奖项为800元,总计额为1835元

解法一:对第一个程序进行改编
 

public class MyThread extends  Thread{
    ArrayList<Integer> list;//静态变量
    //可以利用构造方法
    public MyThread(ArrayList<Integer> list){
        this.list=list;
    }
    //创建两个集合来存放数据
    static  ArrayList<Integer> list1=new ArrayList<>();
   static ArrayList<Integer> list2=new ArrayList<>();
    @Override
    public void run(){
        while(true){
          synchronized (MyThread.class) {
            if(list.size()==0){
                if("抽奖箱1".equals(getName())){
                    System.out.println("抽奖箱1"+list1);
                    int max=0;
                    int count=0;
                    for(int i=0;i<list1.size();i++){
                        if(max<= list1.get(i)){
                            max=list1.get(i);
                        }
                        count+=list1.get(i);
                    }
                    System.out.println("抽奖箱1最大奖"+max);
                    System.out.println("抽奖箱1总计"+count);
                }else if("抽奖箱2".equals(getName())) {
                    System.out.println("抽奖箱2"+list2);
                    int max=0;
                    int count=0;
                    for(int i=0;i<list2.size();i++){
                        if(max<= list2.get(i)){
                            max=list2.get(i);
                        }
                        count+=list2.get(i);
                    }
                    System.out.println("抽奖箱2最大奖"+max);
                    System.out.println("抽奖箱2总计"+count);
                }
                break;
            }else{
                Collections.shuffle(list);//打乱list数据
                int prize=list.remove(0);
               //进行判断
                if("抽奖箱1".equals(getName())){
                    list1.add(prize);
                }else if("抽奖箱2".equals(getName())){
                    list2.add(prize);
                }
            }
        }
}
        try {
            Thread.sleep(10);//目的是可以让两个线程交替进行显示
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

}

解法二:线程栈

public class MyThread extends  Thread {
    ArrayList<Integer> list;//静态变量

    //可以利用构造方法
    public MyThread(ArrayList<Integer> list) {
        this.list = list;
    }

    @Override
    public void run() {
        ArrayList<Integer> List=new ArrayList<>();
        while (true) {
            synchronized (MyThread.class) {
                if (list.size() == 0) {
                    System.out.println(getName()+List);
                    break;
                } else {
                    Collections.shuffle(list);//打乱list数据
                    int prize = list.remove(0);
                    List.add(prize);
                }
            }
            try {
                Thread.sleep(100);//目的是可以让两个线程交替进行显示
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

        }
    }
}

练习4:多线程之间的比较

在上一题基础上继续完成如下需求:在此次抽奖过程中,抽奖箱1总共产生了6个奖项,分别为: 10,20,100,500,2,300,最高奖项为300元,总计额为932元
在此次抽奖过程中,抽奖箱2总共产生了6个奖项,分别为: 5,50,200,800,80,700
最高奖项为800元,总计额为1835元
在此次抽奖过程中,抽奖箱2中产生了最大奖项,该奖项金额为800元
分析:最大奖项应该这两个线程结束后再比较,采用有返回值的线程创建方法,将最大值返回后打印。

public class MyCallable implements Callable<Integer> {
    ArrayList<Integer> list;//静态变量

    //可以利用构造方法
    public MyCallable(ArrayList<Integer> list) {
        this.list = list;
    }

    @Override
    public Integer call() throws Exception {
        ArrayList<Integer> List=new ArrayList<>();
        while (true) {
            synchronized (MyCallable.class) {
                if (list.size() == 0) {
                    System.out.println(Thread.currentThread().getName()+List);
                    break;
                } else {
                    Collections.shuffle(list);//打乱list数据
                    int prize = list.remove(0);
                    List.add(prize);
                }
            }
                Thread.sleep(100);//目的是可以让两个线程交替进行显示
        }
        //把集合中的最大值返回
        if(List.size()==0){
            return null;
        }else{
           return Collections.max(List);
        }

    }
}
public class test1 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ArrayList<Integer> list=new ArrayList<>();
        Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
        MyCallable mc=new MyCallable(list);
        FutureTask<Integer> ft1=new FutureTask<>(mc);
        FutureTask<Integer> ft2=new FutureTask<>(mc);
        Thread t1=new Thread(ft1);
        Thread t2=new Thread(ft2);
        t1.setName("抽奖箱1");
        t2.setName("抽奖箱2");
        t1.start();
        t2.start();
        int max1=ft1.get();
        int max2=ft2.get();
        System.out.println(max1);
        System.out.println(max2);
    }
    }

线程池

核心原理:

创建线程池

创建一个没有上限的线程池:

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 test1 {
    public static void main(String[] args)  {
        //创建线程池对象
      ExecutorService poll= Executors.newCachedThreadPool();
      //提交任务
        poll.submit(new MyRunnable());
        poll.submit(new MyRunnable());
        poll.submit(new MyRunnable());
        //线程池一般不会关闭
    }
    }

 

创建一个有上限的线程池:

public class test1 {
    public static void main(String[] args)  {
        //创建线程池对象
      ExecutorService poll= Executors.newFixedThreadPool(2);
      //提交任务
        poll.submit(new MyRunnable());
        poll.submit(new MyRunnable());
        poll.submit(new MyRunnable());
        //线程池一般不会关闭
    }
    }

自定义线程池

系统先会创建服务于任务1、2、3的线程1、2、3;再将任务4、5、6拿去排队; 再调用临时线程服务于任务7、8、9;任务10会触发任务拒绝策略。

任务拒绝策略

创建自定义线程池:

public class test1 {
    public static void main(String[] args)  {
        //自定义线程池
        ThreadPoolExecutor pool=new ThreadPoolExecutor(
                3,//核心线程的数量
                6,//最大线程数
                60,//空闲线程最大存活时间
                TimeUnit.SECONDS,//时间单位
                new ArrayBlockingQueue<>(3),//任务队列,相当于阻塞队列
                Executors.defaultThreadFactory(),//创建线程工厂:线程池如何获取到一个线程
                new ThreadPoolExecutor.AbortPolicy()//任务拒绝策略
        );
    }
    }

线程池多大合适

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1796245.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

扩散模型会成为深度学习的下一个前沿领域吗?

文章目录 一、说明二、 第 1 部分&#xff1a;了解扩散模型2.1 什么是扩散模型2.2 正向扩散2.3 反向扩散 三、他们的高成本四、扩散模型的用处五、为什么扩散模型如此出色六、第 2 部分&#xff1a;使用扩散模型生成6.1 用于自然语言处理和 LLM 的文本扩散6.2 音频视频生成6.3 …

Hadoop3:MapReduce源码解读之Map阶段的CombineFileInputFormat切片机制(4)

Job那块的断点代码截图省略&#xff0c;直接进入切片逻辑 参考&#xff1a;Hadoop3&#xff1a;MapReduce源码解读之Map阶段的Job任务提交流程&#xff08;1&#xff09; 6、CombineFileInputFormat原理解析 类的继承关系 与TextInputFormat切片机制的区别 框架默认的TextI…

docker构建jdk17镜像

资料参考 参考自黑马教程&#xff1a;10.Docker基础-自定义镜像_哔哩哔哩_bilibili 更多详细语法声明&#xff0c;请参考官网文档&#xff1a;https://docs.docker.com/engine/reference/builder 初步准备 1、下载jdk17包&#xff08;linux版&#xff09;&#xff0c;我这边版…

问题:在本案复议阶段,复议机关()。 #其他#媒体

问题&#xff1a;在本案复议阶段&#xff0c;复议机关&#xff08;&#xff09;。 A&#xff0e;有权责令被申请人纠正违法的征税行为 B&#xff0e;应当对被申请人作出的税务具体行政行为所依据的事实证据、法律程序、法律依据及设定权利义务内容的合法性、适当性进行全面审…

暑期来临,AI智能视频分析方案筑牢防溺水安全屏障

随着夏季暑期的来临&#xff0c;未成年人溺水事故频发。传统的防溺水方式往往依赖于人工巡逻和警示标识的设置&#xff0c;但这种方式存在人力不足、反应速度慢等局限性。近年来&#xff0c;随着视频监控智能分析技术的不断发展&#xff0c;其在夏季防溺水中的应用也日益凸显出…

【十二】图解mybatis日志模块之设计模式

图解mybatis日志模块之设计模式 概述 最近经常在思考研发工程师初、中、高级工程师以及系统架构师各个级别的工程师有什么区别&#xff0c;随着年龄增加我们的技术级别也在提升&#xff0c;但是很多人到了高级别反而更加忧虑&#xff0c;因为it行业35岁年龄是个坎这是行业里的共…

Day30 登录界面设计

​ 本章节,实现了登录界面窗口设计 一.准备登录界面图片素材(透明背景图片) 把准备好的图片放在 Images 文件夹下面,格式分别是 .png和 .icoico 图片,右键属性,生成操作选 内容 png 图片,右键属性,生成操作选 资源 选中 login.png图片鼠标右键,选择属性。生成的操作选…

(学习笔记)数据基建-数据安全

&#xff08;学习笔记&#xff09;数据基建-数据安全 数据安全数据安全实施难点数据安全保障流程数据安全措施实施阶段数据安全如何量化产出数据安全思考 数据安全 数据安全问题是最近比较热的话题&#xff0c;数据泄漏引发的用户信任危机事件也比比皆是&#xff0c;以及跨部门…

windows架设NTP时间服务器进行时间同步

一、windows架设NTP时间服务器 1.win11更改注册表 winR输入regedit 2.HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config&#xff0c;找到Config目录&#xff0c;双击Config目录下的AnnounceFlags&#xff0c;设为5。 3.HKEY_LOCAL_MACHINE\SYSTEM\Current…

Unity + 雷达 粒子互动(待更新)

效果预览: 花海(带移动方向) VFX 实例 脚本示例 使用TouchScript,计算玩家是否移动,且计算移动方向 using System.Collections; using System.Collections.Generic; using TouchScript; using TouchScript.Pointers; using UnityEngine; using UnityEngine.VFX;public …

Java概述 , Java环境安装 , 第一个Hello World

环境变量,HelloWorld 1.会常用的dos命令 2.会安装java所需要的环境(jdk) 3.会配置java的环境变量 4.知道java开发三步骤 5.会java的入门程序(HelloWorld) 6.会三种注释方式 7.知道Java入门程序所需要注意的地方 8.知道println和print的区别第一章 Java概述 1.1 JavaSE体系介绍…

【干货】视频文件抽帧(opencv和ffmpeg方式对比)

1 废话不多说&#xff0c;直接上代码 opencv方式 import time import subprocess import cv2, os from math import ceildef extract_frames_opencv(video_path, output_folder, frame_rate1):"""使用 OpenCV 从视频中抽取每秒指定帧数的帧,并保存到指定文件夹…

关于队列的知识点以及例题讲解

本篇文章将带大家学习队列的相关知识点&#xff0c;并且讲解几道例题&#xff0c;请各位小伙伴耐心观看 队列的概念 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表 遵循原则 先进先出 队列的实现 图解&#xff1a; 代码实…

性能监控工具

性能是任何一款软件都需要关注的重要指标。除了软件的基本功 能&#xff0c;性能可以说是评价软件优劣的最重要的指标之一。我们该如何有 效地监控和诊断性能问题呢?本章基于实践&#xff0c;着重介绍一些针对系统 和Java虚拟机的监控和诊断工具&#xff0c;以帮助读者在实际开…

软件测试——蓝桥杯笔记(自用)

Before和BeforeClass&#xff0c;在测试前&#xff0c;初始化Driver&#xff0c;BeforeClass适用于静态方法 After和AfterClass&#xff0c;在测试后&#xff0c;关闭Driver&#xff0c;AfterClass适用于静态方法 自动化测试记得使用BeforeClass&#xff0c;AfterClass 单元…

Linux应用 sqlite3编程

1、概念 SQLite3是一个轻量级的、自包含的、基于文件的数据库管理系统&#xff0c;常用于移动设备、嵌入式设备和小型应用程序中&#xff0c;应用场景如下&#xff1a; 移动应用程序&#xff1a;由于SQLite3是零配置、无服务器的数据库引擎&#xff0c;非常适合用于移动应用程…

【MySQL调优】如何进行MySQL调优?从参数、数据建模、索引、SQL语句等方向,三万字详细解读MySQL的性能优化方案(2024版)

导航&#xff1a; 本文一些内容需要聚簇索引、非聚簇索引、B树、覆盖索引、索引下推等前置概念&#xff0c;虽然本文有简单回顾&#xff0c;但详细可以参考下文的【MySQL高级篇】 【Java笔记踩坑汇总】Java基础进阶JavaWebSSMSpringBoot瑞吉外卖SpringCloud黑马旅游谷粒商城学成…

[Cesium]加载GeoJSON并自定义设置符号(以点要素为例)

数据准备&#xff1a; Geoserver发布WFS&#xff08;Web Feature Service&#xff09;服务 [GeoServer系列]Shapefile数据发布-CSDN博客 数据加载&#xff1a; 数据准备第二种方式加载数据&#xff0c;利用for循环加载多个图层。首先将获取数据(每获取一次获得pomise,将其加入…

SQL优化系列-快速学会分析SQL执行效率(下)

1 show profile 分析慢查询 有时需要确定 SQL 到底慢在哪个环节&#xff0c;此时 explain 可能不好确定。在 MySQL 数据库中&#xff0c;通过 profile&#xff0c;能够更清楚地了解 SQL 执行过程的资源使用情况&#xff0c;能让我们知道到底慢在哪个环节。 知识扩展&#xff1…

Wireshark 如何查找包含特定数据的数据帧

1、查找包含特定 string 的数据帧 使用如下指令&#xff1a; 双引号中所要查找的字符串 frame contains "xxx" 查找字符串 “heartbeat” 示例&#xff1a; 2、查找包含特定16进制的数据帧 使用如下指令&#xff1a; TCP&#xff1a;在TCP流中查找 tcp contai…