uacs2024

导航

Java基础4 线程

 

创建线程

CreateThreadDemo1.java    继承Thread类

/**
 * 1、启动线程必须是调用start方法,不是调用run方法。
 *      直接调用run方法会当成普通方法执行,此时相当于还是单线程执行,
 *      只有调用start方法才是启动一个新的线程执行。
 * 2、不要把主线程任务放在启动子线程之前
 *      这样主线程一直是先跑完的,相当于是一个单线程的效果了,
 */
public class CreateThreadDemo1 {
    public static void main(String[] args) {
        //目标:认识多线程,掌握创建线程的方式一:继承Thread类来实现
        //4、创建线程类的对象:代表线程。
        MyThread mt = new MyThread();
        mt.start();
        for (int i = 0; i < 10; i++) {
            System.out.println("主线程main输出:" + i);
        }
    }
}

/**
 * 1、定义一个子类继承Thread类,成为一个线程类
 * 优点:编码简单
 * 缺点:线程类已经继承Thread,无法继承其他类,不利于功能的扩展
 * 假如线程执行完毕后有一些数据需要返回,他们重写的run方法均不能直接返回结果
 */
class MyThread extends Thread{
    //2、重写run方法,将线程要执行的代码放入run方法中。
    @Override
    public void run() {
        //3、调用start方法开启线程。在run方法中编写要执行的代码(线程要干的活)。
        for (int i = 0; i < 10; i++) {
            System.out.println("子线程MyThread输出:" + i);
        }
    }
}

res

主线程main输出:0
主线程main输出:1
主线程main输出:2
子线程MyThread输出:0
子线程MyThread输出:1
主线程main输出:3
子线程MyThread输出:2
主线程main输出:4
子线程MyThread输出:3
主线程main输出:5
子线程MyThread输出:4
主线程main输出:6
子线程MyThread输出:5
主线程main输出:7
子线程MyThread输出:6
主线程main输出:8
子线程MyThread输出:7
主线程main输出:9
子线程MyThread输出:8
子线程MyThread输出:9

 

CreateThreadDemo2.java    实现Runnable接口

public class CreateThreadDemo2 {
    public static void main(String[] args) {
        //目标:掌握多线程的创建方式二:实现Runnable接口来创建。
        test1();
        System.out.println("---------------------------------------------------");
        test2();
    }

    private static void test2() {
        Runnable r = new Runnable(){
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("匿名线程任务类1输出:" + i);
                }
            }
        };
        Thread t = new Thread(r);
        t.start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("匿名线程任务类2输出:" + i);
                }
            }
        }).start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                System.out.println("匿名线程任务类3输出:" + i);
            }
        }).start();

        for (int i = 0; i < 10; i++) {
            System.out.println("主线程test2输出:" + i);
        }

    }

    public static void test1(){
        //3、创建线程任务类的对象代表一个线程任务。
        MyRunnable mr = new MyRunnable();
        //4、创建线程类的对象:代表线程。把线程任务对象作为构造方法参数传递给Thread类的构造方法
        Thread t = new Thread(mr);
        t.start();
        for (int i = 0; i < 10; i++) {
            System.out.println("主线程test1输出:" + i);
        }
    }
}

/**
 * 创建线程的第二种方式:定义一个线程任务类实现Runnable接口
 * 优点:任务类只是实现接口,可以继续继承其他类、实现其他接口,扩展性强
 * 缺点:需要多一个Runnable对象
 * 假如线程执行完毕后有一些数据需要返回,他们重写的run方法均不能直接返回结果
 */
class MyRunnable implements Runnable {
    //重写run方法,将线程要执行的代码放入run方法中。
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("线程任务类MyRunnable输出:" + i);
        }
    }
}

res

线程任务类MyRunnable输出:0
主线程test1输出:0
线程任务类MyRunnable输出:1
主线程test1输出:1
线程任务类MyRunnable输出:2
主线程test1输出:2
线程任务类MyRunnable输出:3
主线程test1输出:3
线程任务类MyRunnable输出:4
主线程test1输出:4
线程任务类MyRunnable输出:5
主线程test1输出:5
线程任务类MyRunnable输出:6
主线程test1输出:6
线程任务类MyRunnable输出:7
主线程test1输出:7
线程任务类MyRunnable输出:8
主线程test1输出:8
主线程test1输出:9
线程任务类MyRunnable输出:9
---------------------------------------------------
匿名线程任务类1输出:0
匿名线程任务类1输出:1
匿名线程任务类1输出:2
匿名线程任务类1输出:3
匿名线程任务类1输出:4
匿名线程任务类1输出:5
匿名线程任务类1输出:6
匿名线程任务类1输出:7
匿名线程任务类1输出:8
匿名线程任务类1输出:9
匿名线程任务类2输出:0
匿名线程任务类2输出:1
匿名线程任务类2输出:2
匿名线程任务类2输出:3
匿名线程任务类2输出:4
匿名线程任务类2输出:5
匿名线程任务类2输出:6
匿名线程任务类2输出:7
匿名线程任务类2输出:8
匿名线程任务类2输出:9
主线程test2输出:0
主线程test2输出:1
主线程test2输出:2
主线程test2输出:3
主线程test2输出:4
主线程test2输出:5
主线程test2输出:6
主线程test2输出:7
匿名线程任务类3输出:0
匿名线程任务类3输出:1
主线程test2输出:8
匿名线程任务类3输出:2
匿名线程任务类3输出:3
主线程test2输出:9
匿名线程任务类3输出:4
匿名线程任务类3输出:5
匿名线程任务类3输出:6
匿名线程任务类3输出:7
匿名线程任务类3输出:8
匿名线程任务类3输出:9

 

CreateThreadDemo3.java    定义类实现Callable接口,重写call方法。Callable类型对象封装成FutureTask,再把FutureTask交给Thread对象

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
/**
 * 1.创建任务对象
 *      定义一个类实现Callable接口,重写call方法,封装要做的事情,和要返回的数据。
 *      把Callable类型的对象封装成FutureTask(线程任务对象)。
 * 2.把线程任务对象交给Thread对象:
 * 3.调用Thread对象的start方法启动线程
 * 4.线程执行完毕后、通过FutureTask对象的的get方法去获取线程任务执行的结果
 */
public class CreateThreadDemo3 {
    public static void main(String[] args) {
        //目标:掌握多线程的创建方式三:实现Callable接口,方式三的优势:可以获取线程执行完毕后的结果的。
        //3.创建一个Callable接日的实现类对象。
        Callable<String> c1 = new MyCallable(20);
        //4.把Callable对象封装成一个真正的线程任务对象FutureTask对象。
        /**
         * 未来任务对象的作用?
         *     1.本质上是一个Runnable线程任务对象,可以交给Thread线程对象处理
         *     2.可以获取线程执行完毕后的结果。
         */
        FutureTask<String> ft1 = new FutureTask<>(c1);//public FutureTask(Callable<V> callable)
        //5.创建一个Thread对象,把FutureTask对象作为构造参数传递。
        Thread t1 = new Thread(ft1);//public Thread(Runnable target)
        //Thread t1 = new Thread(ft1, "线程1");//public Thread(Runnable target)
        //6.启动线程。
        t1.start();

        Callable<String> c2 = new MyCallable(30);
        FutureTask<String> ft2 = new FutureTask<String>(c2);//public FutureTask(Callable<V> callable)
        Thread t2 = new Thread(ft2);//public Thread(Runnable target)
        //Thread t2 = new Thread(ft2, "线程2");//public Thread(Runnable target)
        t2.start();

        //获取线程执行完毕后返回的结果
        //分开try-catch。因为如果是第一个get拿到异常就不会往下执行了 会导致第二个get的异常(如果有)被忽略
        try {
            //如果主线程发现第一个线程还没有执行完毕,会让出CPU,等第一个线程执行完毕后,才会往下执行!
            System.out.println(ft1.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            System.out.println(ft2.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

//1.定义一个实现类实现Callable接口
class MyCallable implements Callable<String> {
    private int n;
    public MyCallable(int n) { this.n = n; }
    //2.实现call方法,将线程要执行的代码放入call方法中。
    @Override
    public String call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= n; i++) {
            System.out.println("子线程MyCallable 1--" + n + "的call方法输出:" + i);
            sum += i;
        }
        return "========================子线程MyCallable 1--" + n + "的最终输出:" + sum + "========================";
    }
}

res

子线程MyCallable 1--30的call方法输出:1
子线程MyCallable 1--20的call方法输出:1
子线程MyCallable 1--20的call方法输出:2
子线程MyCallable 1--30的call方法输出:2
子线程MyCallable 1--30的call方法输出:3
子线程MyCallable 1--30的call方法输出:4
子线程MyCallable 1--20的call方法输出:3
子线程MyCallable 1--30的call方法输出:5
子线程MyCallable 1--30的call方法输出:6
子线程MyCallable 1--30的call方法输出:7
子线程MyCallable 1--30的call方法输出:8
子线程MyCallable 1--20的call方法输出:4
子线程MyCallable 1--30的call方法输出:9
子线程MyCallable 1--20的call方法输出:5
子线程MyCallable 1--30的call方法输出:10
子线程MyCallable 1--20的call方法输出:6
子线程MyCallable 1--30的call方法输出:11
子线程MyCallable 1--20的call方法输出:7
子线程MyCallable 1--30的call方法输出:12
子线程MyCallable 1--20的call方法输出:8
子线程MyCallable 1--30的call方法输出:13
子线程MyCallable 1--20的call方法输出:9
子线程MyCallable 1--30的call方法输出:14
子线程MyCallable 1--20的call方法输出:10
子线程MyCallable 1--30的call方法输出:15
子线程MyCallable 1--20的call方法输出:11
子线程MyCallable 1--30的call方法输出:16
子线程MyCallable 1--20的call方法输出:12
子线程MyCallable 1--30的call方法输出:17
子线程MyCallable 1--20的call方法输出:13
子线程MyCallable 1--30的call方法输出:18
子线程MyCallable 1--20的call方法输出:14
子线程MyCallable 1--30的call方法输出:19
子线程MyCallable 1--20的call方法输出:15
子线程MyCallable 1--30的call方法输出:20
子线程MyCallable 1--20的call方法输出:16
子线程MyCallable 1--30的call方法输出:21
子线程MyCallable 1--20的call方法输出:17
子线程MyCallable 1--30的call方法输出:22
子线程MyCallable 1--20的call方法输出:18
子线程MyCallable 1--30的call方法输出:23
子线程MyCallable 1--20的call方法输出:19
子线程MyCallable 1--30的call方法输出:24
子线程MyCallable 1--20的call方法输出:20
子线程MyCallable 1--30的call方法输出:25
子线程MyCallable 1--30的call方法输出:26
子线程MyCallable 1--30的call方法输出:27
子线程MyCallable 1--30的call方法输出:28
子线程MyCallable 1--30的call方法输出:29
子线程MyCallable 1--30的call方法输出:30
========================子线程MyCallable 1--20的最终输出:210========================
========================子线程MyCallable 1--30的最终输出:465========================

 

线程常用API

ThreadApiDemo1.java    线程名称

public class ThreadApiDemo1 {
    public static void main(String[] args) {
        //目标:理解Thread类中的常用方法。
        Thread t1 = new MyThread("线程1");
        Thread t2 = new MyThread("线程2");
        //t1.setName("线程1");t2.setName("线程2");
        System.out.println(t1.getName());//线程默认名称是:Thread-索引
        System.out.println(t2.getName());//线程默认名称是:Thread-索引

        t1.start();
        t2.start();

        Thread m = Thread.currentThread();//哪个线程调用这个代码,这个代码就拿到哪个线程
        m.setName("主线程");
        System.out.println(m.getName());//main
    }
}

class MyThread extends Thread{
    public MyThread(String name) { super(name);//public Thread(String name)
    }

    //2、重写run方法,将线程要执行的代码放入run方法中。
    @Override
    public void run() {
        //3、调用start方法开启线程。在run方法中编写要执行的代码(线程要干的活)。
        for (int i = 0; i < 20; i++) {
            System.out.println(getName() + "-MyThread输出:" + i);
        }
    }
}

res

线程1
线程2
主线程
线程1-MyThread输出:0
线程1-MyThread输出:1
线程2-MyThread输出:0
线程1-MyThread输出:2
线程2-MyThread输出:1
线程1-MyThread输出:3
线程2-MyThread输出:2
线程1-MyThread输出:4
线程1-MyThread输出:5
线程2-MyThread输出:3
线程1-MyThread输出:6
线程2-MyThread输出:4
线程1-MyThread输出:7
线程2-MyThread输出:5
线程1-MyThread输出:8
线程2-MyThread输出:6
线程1-MyThread输出:9
线程2-MyThread输出:7
线程2-MyThread输出:8
线程2-MyThread输出:9

 

ThreadApiDemo2.java    线程休眠

public class ThreadApiDemo2 {
    public static void main(String[] args) {
        //目标:搞清楚Thread类的Sleep方法(线程休眠)
        for (int i = 0; i < 100; i++) {
            System.out.println("线程1输出:" + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

 

 

ThreadApiDemo3.java    线程插队

public class ThreadApiDemo3 {
    public static void main(String[] args) {
        //目标:搞清楚线程的join方法:线程插队:让调用这个方法线程先执行完毕。
        MyThread2 t1 = new MyThread2("线程1");
        t1.start();

        for(int i = 0; i < 20; i++){
            System.out.println(Thread.currentThread().getName() + "-主线程输出:" + i);
            if(i == 12){
                try {
                    t1.join();//让线程1先执行完毕。
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

class MyThread2 extends Thread{
    public MyThread2(String name){ super(name);//public Thread(String name)
    }

    //2、重写run方法,将线程要执行的代码放入run方法中。
    @Override
    public void run() {
        //3、调用start方法开启线程。在run方法中编写要执行的代码(线程要干的活)。
        for (int i = 0; i < 20; i++) {
            System.out.println(getName() + "-MyThread输出:" + i);
        }
    }
}

res

main-主线程输出:0
main-主线程输出:1
main-主线程输出:2
main-主线程输出:3
main-主线程输出:4
main-主线程输出:5
main-主线程输出:6
main-主线程输出:7
线程1-MyThread输出:0
线程1-MyThread输出:1
main-主线程输出:8
线程1-MyThread输出:2
main-主线程输出:9
线程1-MyThread输出:3
main-主线程输出:10
线程1-MyThread输出:4
main-主线程输出:11
线程1-MyThread输出:5
main-主线程输出:12
线程1-MyThread输出:6
线程1-MyThread输出:7
线程1-MyThread输出:8
线程1-MyThread输出:9
线程1-MyThread输出:10
线程1-MyThread输出:11
线程1-MyThread输出:12
线程1-MyThread输出:13
线程1-MyThread输出:14
线程1-MyThread输出:15
线程1-MyThread输出:16
线程1-MyThread输出:17
线程1-MyThread输出:18
线程1-MyThread输出:19
main-主线程输出:13
main-主线程输出:14
main-主线程输出:15
main-主线程输出:16
main-主线程输出:17
main-主线程输出:18
main-主线程输出:19

 

 

线程安全

ThreadSafeDemo1.java    模拟线程安全问题

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

public class ThreadSafeDemo1 {
    public static void main(String[] args) {
        //目标:模拟线程安全问题。
        Account acc = new Account("6226 0000 0000 0000", 100000);
        //2、设计线程类:创建小明和小红两个线程,模拟小明和小红同时去同一个账户取款10万。
        new DrawMoneyThread("小明线程", acc).start();
        new DrawMoneyThread("小红线程", acc).start();
    }
}

class DrawMoneyThread extends Thread{
    private Account acc;
    public DrawMoneyThread(String name, Account acc) {
        super(name);this.acc = acc;
    }

    @Override
    public void run() { acc.drawMoney(100000); }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class Account{
    private String cardId;
    private double money;

    public void drawMoney(double money){
        String name = Thread.currentThread().getName();
        if(this.money >= money){
            System.out.println(name + "取款成功,吐出钞票" + money);
            this.money -= money;
            System.out.println("账户余额为:" + this.money);
        }else{
            System.out.println(name + "取款失败,账户余额不足");
        }
    }
}

res

小红线程取款成功,吐出钞票100000.0
小明线程取款成功,吐出钞票100000.0
账户余额为:0.0
账户余额为:-100000.0

 

 

SynchronizedCodeDemo1.java      线程安全方法一:同步代码块

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

public class SynchronizedCodeDemo1 {
    public static void main(String[] args) {
        //目标:线程同步方式一:同步代码块
        Account acc = new Account("6226 0000 0000 0000", 100000);
        //2、设计线程类:创建小明和小红两个线程,模拟小明和小红同时去同一个账户取款10万。
        new DrawMoneyThread("小明线程", acc).start();
        new DrawMoneyThread("小红线程", acc).start();
    }
}

class DrawMoneyThread extends Thread{
    private Account acc;
    public DrawMoneyThread(String name, Account acc) {
        super(name);this.acc = acc;
    }

    @Override
    public void run() { acc.drawMoney(100000); }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class Account{
    private String cardId;
    private double money;

    public void drawMoney(double money){
        String name = Thread.currentThread().getName();

        /**
         * 就比如拿一家四口举例,“dlei”是常量池里的唯一一份(独占一份空间),但是你每次new object就会创造出不同内存的对象
         * 建议使用共享资源作为锁对象,对于实例方法建议使用this作为锁对象
         * 对于静态方法建议使用字节码(类名.class)对象作为锁对象。
         * 对出现问题的核心代码使用synchronized进行加锁,每次只能一个线程占锁进入访问*/
        synchronized (this) {
            if(this.money >= money){
                System.out.println(name + "取款成功,吐出钞票" + money);
                this.money -= money;
                System.out.println("账户余额为:" + this.money);
            }else{
                System.out.println(name + "取款失败,账户余额不足");
            }
        }
    }
}

res

小明线程取款成功,吐出钞票100000.0
账户余额为:0.0
小红线程取款失败,账户余额不足

 

 

SynchronizedMethodDemo1.java      线程安全方法二:同步方法

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

public class SynchronizedMethodDemo1 {
    public static void main(String[] args) {
        //目标:线程同步方式二:同步方法
        Account acc = new Account("6226 0000 0000 0000", 100000);
        //2、设计线程类:创建小明和小红两个线程,模拟小明和小红同时去同一个账户取款10万。
        new DrawMoneyThread("小明线程", acc).start();
        new DrawMoneyThread("小红线程", acc).start();
    }
}

class DrawMoneyThread extends Thread{
    private Account acc;
    public DrawMoneyThread(String name, Account acc) {
        super(name);this.acc = acc;
    }

    @Override
    public void run() { acc.drawMoney(100000); }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class Account{
    private String cardId;
    private double money;

    //对出现问题的核心方法使用synchronized修饰
    //每次只能一个线程占锁进入访问
    public synchronized void drawMoney(double money){
        String name = Thread.currentThread().getName();

        if(this.money >= money){
            System.out.println(name + "取款成功,吐出钞票" + money);
            this.money -= money;
            System.out.println("账户余额为:" + this.money);
        }else{
            System.out.println(name + "取款失败,账户余额不足");
        }
    }
}

res

小明线程取款成功,吐出钞票100000.0
账户余额为:0.0
小红线程取款失败,账户余额不足

 

 

LockDemo1.java      线程安全方法三:Lock锁

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockDemo1 {
    public static void main(String[] args) {
        //目标:线程同步方式三:Lock锁
        //锁对象建议使用final修饰,防止被别人篡改
        //建议将释放锁的操作放到finally代码块中,确保锁用完了一定会被释放
        Account acc = new Account("6226 0000 0000 0000", 100000);
        //2、设计线程类:创建小明和小红两个线程,模拟小明和小红同时去同一个账户取款10万。
        new DrawMoneyThread("小明线程", acc).start();
        new DrawMoneyThread("小红线程", acc).start();
    }
}

class DrawMoneyThread extends Thread{
    private Account acc;
    public DrawMoneyThread(String name, Account acc) {
        super(name);this.acc = acc;
    }

    @Override
    public void run() { acc.drawMoney(100000); }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class Account{
    private String cardId;
    private double money;
    private final Lock lk = new ReentrantLock();//一个账户对应一把锁,不能声明为static,因为锁是属于账户对象的,而不是类的。final是为了保护锁对象

    public void drawMoney(double money){
        String name = Thread.currentThread().getName();
        lk.lock();
        try {
            if(this.money >= money){
                System.out.println(name + "取款成功,吐出钞票" + money);
                this.money -= money;
                System.out.println("账户余额为:" + this.money);
            }else{
                System.out.println(name + "取款失败,账户余额不足");
            }
        } finally {
            lk.unlock();//防止代码执行过程中出现异常无法解锁
        }
    }
}

res

小明线程取款成功,吐出钞票100000.0
账户余额为:0.0
小红线程取款失败,账户余额不足

 

 

线程池

ExecutorsDemo3.java      调用线程池工具类Executors的静态方法得到线程池

import java.util.concurrent.*;

/**
 * public static ExecutorService newFixedThreadPool(int nThreads)
 *      创建固定线程数量的线程池,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程替代它。
 * public static ExecutorService newSingleThreadExecutor()
 *      创建只有一个线程的线程池对象,如果该线程出现异常而结束,那么线程池会补充一个新线程。
 * public static ExecutorService newCachedThreadPool()
 *      线程数量随着任务增加而增加,如果线程任务执行完毕且空闲了60s则会被回收掉。
 * public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
 *      创建一个线程池,可以实现在给定的延迟后运行任务或者定期执行任务。
 * 注意 :这些方法的底层,都是通过线程池的实现类ThreadPoolExecutor创建的线程池对象
 * Executors是否适合做大型互联网场景的线程池方案?
 *      不合适。建议使用ThreadPoolExecutor来指定线程池参数,这样可以明确线程池的运行规则,规避资源耗尽的风险*/

public class ExecutorsDemo3 {
    public static void main(String[] args) {
        //目标:通过线程池工具类:Executors,调用其静态方法直接得到线程池
        ExecutorService pool = Executors.newFixedThreadPool(3);

        Future<String> f1 = pool.submit(new MyCallable2(20));
        Future<String> f2 = pool.submit(new MyCallable2(21));
        Future<String> f3 = pool.submit(new MyCallable2(22));
        Future<String> f4 = pool.submit(new MyCallable2(25));

        try {
            System.out.println(f1.get());
            System.out.println(f2.get());
            System.out.println(f3.get());
            System.out.println(f4.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }finally {
            pool.shutdown();
        }

    }
}

class MyCallable2 implements Callable<String> {
    private int n;
    public MyCallable2(int n) { this.n = n; }
    //2.实现call方法,将线程要执行的代码放入call方法中。
    @Override
    public String call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= n; i++) {
            System.out.println(Thread.currentThread().getName() + "子线程MyCallable 1--" + n + "的call方法输出:" + i);sum += i;
        }
        return "==============================" + Thread.currentThread().getName() + "子线程MyCallable 1--" + n + "的最终输出:" + sum + "==============================";
    }
}

res

pool-1-thread-2子线程MyCallable 1--21的call方法输出:1
pool-1-thread-2子线程MyCallable 1--21的call方法输出:2
pool-1-thread-2子线程MyCallable 1--21的call方法输出:3
pool-1-thread-3子线程MyCallable 1--22的call方法输出:1
pool-1-thread-2子线程MyCallable 1--21的call方法输出:4
pool-1-thread-1子线程MyCallable 1--20的call方法输出:1
pool-1-thread-2子线程MyCallable 1--21的call方法输出:5
pool-1-thread-3子线程MyCallable 1--22的call方法输出:2
pool-1-thread-2子线程MyCallable 1--21的call方法输出:6
pool-1-thread-1子线程MyCallable 1--20的call方法输出:2
pool-1-thread-2子线程MyCallable 1--21的call方法输出:7
pool-1-thread-1子线程MyCallable 1--20的call方法输出:3
pool-1-thread-3子线程MyCallable 1--22的call方法输出:3
pool-1-thread-1子线程MyCallable 1--20的call方法输出:4
pool-1-thread-2子线程MyCallable 1--21的call方法输出:8
pool-1-thread-1子线程MyCallable 1--20的call方法输出:5
pool-1-thread-3子线程MyCallable 1--22的call方法输出:4
pool-1-thread-1子线程MyCallable 1--20的call方法输出:6
pool-1-thread-2子线程MyCallable 1--21的call方法输出:9
pool-1-thread-1子线程MyCallable 1--20的call方法输出:7
pool-1-thread-3子线程MyCallable 1--22的call方法输出:5
pool-1-thread-1子线程MyCallable 1--20的call方法输出:8
pool-1-thread-2子线程MyCallable 1--21的call方法输出:10
pool-1-thread-1子线程MyCallable 1--20的call方法输出:9
pool-1-thread-3子线程MyCallable 1--22的call方法输出:6
pool-1-thread-1子线程MyCallable 1--20的call方法输出:10
pool-1-thread-2子线程MyCallable 1--21的call方法输出:11
pool-1-thread-1子线程MyCallable 1--20的call方法输出:11
pool-1-thread-3子线程MyCallable 1--22的call方法输出:7
pool-1-thread-1子线程MyCallable 1--20的call方法输出:12
pool-1-thread-2子线程MyCallable 1--21的call方法输出:12
pool-1-thread-1子线程MyCallable 1--20的call方法输出:13
pool-1-thread-3子线程MyCallable 1--22的call方法输出:8
pool-1-thread-1子线程MyCallable 1--20的call方法输出:14
pool-1-thread-2子线程MyCallable 1--21的call方法输出:13
pool-1-thread-1子线程MyCallable 1--20的call方法输出:15
pool-1-thread-3子线程MyCallable 1--22的call方法输出:9
pool-1-thread-1子线程MyCallable 1--20的call方法输出:16
pool-1-thread-2子线程MyCallable 1--21的call方法输出:14
pool-1-thread-1子线程MyCallable 1--20的call方法输出:17
pool-1-thread-3子线程MyCallable 1--22的call方法输出:10
pool-1-thread-1子线程MyCallable 1--20的call方法输出:18
pool-1-thread-2子线程MyCallable 1--21的call方法输出:15
pool-1-thread-1子线程MyCallable 1--20的call方法输出:19
pool-1-thread-3子线程MyCallable 1--22的call方法输出:11
pool-1-thread-1子线程MyCallable 1--20的call方法输出:20
pool-1-thread-2子线程MyCallable 1--21的call方法输出:16
pool-1-thread-3子线程MyCallable 1--22的call方法输出:12
pool-1-thread-3子线程MyCallable 1--22的call方法输出:13
pool-1-thread-2子线程MyCallable 1--21的call方法输出:17
pool-1-thread-3子线程MyCallable 1--22的call方法输出:14
pool-1-thread-2子线程MyCallable 1--21的call方法输出:18
pool-1-thread-3子线程MyCallable 1--22的call方法输出:15
pool-1-thread-2子线程MyCallable 1--21的call方法输出:19
pool-1-thread-3子线程MyCallable 1--22的call方法输出:16
pool-1-thread-2子线程MyCallable 1--21的call方法输出:20
pool-1-thread-3子线程MyCallable 1--22的call方法输出:17
pool-1-thread-2子线程MyCallable 1--21的call方法输出:21
pool-1-thread-3子线程MyCallable 1--22的call方法输出:18
pool-1-thread-3子线程MyCallable 1--22的call方法输出:19
pool-1-thread-3子线程MyCallable 1--22的call方法输出:20
pool-1-thread-3子线程MyCallable 1--22的call方法输出:21
pool-1-thread-3子线程MyCallable 1--22的call方法输出:22
pool-1-thread-3子线程MyCallable 1--25的call方法输出:1
pool-1-thread-3子线程MyCallable 1--25的call方法输出:2
pool-1-thread-3子线程MyCallable 1--25的call方法输出:3
pool-1-thread-3子线程MyCallable 1--25的call方法输出:4
==============================pool-1-thread-1子线程MyCallable 1--20的最终输出:210==============================
==============================pool-1-thread-2子线程MyCallable 1--21的最终输出:231==============================
==============================pool-1-thread-3子线程MyCallable 1--22的最终输出:253==============================
pool-1-thread-3子线程MyCallable 1--25的call方法输出:5
pool-1-thread-3子线程MyCallable 1--25的call方法输出:6
pool-1-thread-3子线程MyCallable 1--25的call方法输出:7
pool-1-thread-3子线程MyCallable 1--25的call方法输出:8
pool-1-thread-3子线程MyCallable 1--25的call方法输出:9
pool-1-thread-3子线程MyCallable 1--25的call方法输出:10
pool-1-thread-3子线程MyCallable 1--25的call方法输出:11
pool-1-thread-3子线程MyCallable 1--25的call方法输出:12
pool-1-thread-3子线程MyCallable 1--25的call方法输出:13
pool-1-thread-3子线程MyCallable 1--25的call方法输出:14
pool-1-thread-3子线程MyCallable 1--25的call方法输出:15
pool-1-thread-3子线程MyCallable 1--25的call方法输出:16
pool-1-thread-3子线程MyCallable 1--25的call方法输出:17
pool-1-thread-3子线程MyCallable 1--25的call方法输出:18
pool-1-thread-3子线程MyCallable 1--25的call方法输出:19
pool-1-thread-3子线程MyCallable 1--25的call方法输出:20
pool-1-thread-3子线程MyCallable 1--25的call方法输出:21
pool-1-thread-3子线程MyCallable 1--25的call方法输出:22
pool-1-thread-3子线程MyCallable 1--25的call方法输出:23
pool-1-thread-3子线程MyCallable 1--25的call方法输出:24
pool-1-thread-3子线程MyCallable 1--25的call方法输出:25
==============================pool-1-thread-3子线程MyCallable 1--25的最终输出:325==============================

 

 

ExecutorServiceDemo1.java      线程池对象

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * ThreadPoolExecutor构造方法各个参数含义:
 *      参数一:corePoolSize:指定线程池的核心线程数量
 *      参数二:maximumPoolSize:指定线程池的最大线程数量
 *      参数三:keepAliveTime:指定临时线程的存活时间
 *      参数四:unit:指定临时线程存活的时间单位(秒、分、时、天)
 *      参数五:workQueue:指定线程池的任务队列
 *      参数六:threadFactory:指定线程池的线程工厂
 *      参数七:handler:指定线程池的任务拒绝策略(线程都在忙,任务队列也满了的时候,新任务来了该怎么处理)
 */

/**
 * 临时线程创建条件:1.有定义临时线程的名额 2.核心线程都在工作
 *                3.任务队列满员        4.有新任务尝试加入任务队列
 * 什么时候拒绝新任务?
 *               核心线程和临时线程都在忙,新任务来了,就拒绝新任务。
 */

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

public class ExecutorServiceDemo1 {
    public static void main(String[] args) {
        //目标:创建线程池对象来使用。
        //1、使用线程池的实现类ThreadPoolExecutor声明七个参数来创建线程对象。
        ThreadPoolExecutor pool = new ThreadPoolExecutor(
                3,//参数一:corePoolSize:指定线程池的核心线程的数量
                5,//参数二:maximumPoolSize:指定线程池的最大线程数量
                10,//参数三:keepAliveTime:指定临时线程的存活时间
                TimeUnit.SECONDS,//参数四:unit:指定临时线程存活的时间单位(秒、分、时、天)
                new ArrayBlockingQueue<>(3),//参数五:workQueue:指定线程池的任务队列
                Executors.defaultThreadFactory(),//参数六:threadFactory:指定线程池的线程工厂
                new ThreadPoolExecutor.AbortPolicy()//参数七:handler:指定线程池的任务拒绝策略
        );

        //2.使用线程池处理任务
        Runnable target = new MyRunnable();
        pool.execute(target);//提交第1个任务,创建第1个线程,自动启动线程处理这个任务。
        pool.execute(target);//提交第2个任务,创建第2个线程,自动启动线程处理这个任务。
        pool.execute(target);//提交第3个任务,创建第3个线程,自动启动线程处理这个任务。
        pool.execute(target);//复用线程
        pool.execute(target);//复用线程
        pool.execute(target);//复用线程

        //3、关闭线程池,不过一般不关闭线程池。
        //pool.shutdown();//等所有任务执行完毕后再关闭线程池!

        //pool.shutdownNow();//立刻关闭线程池,并清空任务队列,并中断正在运行的线程。
    }
}

class MyRunnable implements Runnable {
    //重写run方法,将线程要执行的代码放入run方法中。
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName() + " 线程任务类MyRunnable输出:" + i);
        }
        System.out.println("=========================" + Thread.currentThread().getName() + "线程任务类MyRunnable执行完毕!=========================");
    }
}

res

pool-1-thread-3 线程任务类MyRunnable输出:0
pool-1-thread-2 线程任务类MyRunnable输出:0
pool-1-thread-1 线程任务类MyRunnable输出:0
pool-1-thread-2 线程任务类MyRunnable输出:1
pool-1-thread-3 线程任务类MyRunnable输出:1
pool-1-thread-2 线程任务类MyRunnable输出:2
pool-1-thread-1 线程任务类MyRunnable输出:1
pool-1-thread-2 线程任务类MyRunnable输出:3
pool-1-thread-3 线程任务类MyRunnable输出:2
pool-1-thread-2 线程任务类MyRunnable输出:4
pool-1-thread-1 线程任务类MyRunnable输出:2
pool-1-thread-2 线程任务类MyRunnable输出:5
pool-1-thread-3 线程任务类MyRunnable输出:3
pool-1-thread-2 线程任务类MyRunnable输出:6
pool-1-thread-1 线程任务类MyRunnable输出:3
pool-1-thread-2 线程任务类MyRunnable输出:7
pool-1-thread-3 线程任务类MyRunnable输出:4
pool-1-thread-2 线程任务类MyRunnable输出:8
pool-1-thread-1 线程任务类MyRunnable输出:4
pool-1-thread-2 线程任务类MyRunnable输出:9
pool-1-thread-3 线程任务类MyRunnable输出:5
pool-1-thread-2 线程任务类MyRunnable输出:10
pool-1-thread-1 线程任务类MyRunnable输出:5
pool-1-thread-2 线程任务类MyRunnable输出:11
pool-1-thread-3 线程任务类MyRunnable输出:6
pool-1-thread-2 线程任务类MyRunnable输出:12
pool-1-thread-1 线程任务类MyRunnable输出:6
pool-1-thread-2 线程任务类MyRunnable输出:13
pool-1-thread-3 线程任务类MyRunnable输出:7
pool-1-thread-2 线程任务类MyRunnable输出:14
pool-1-thread-1 线程任务类MyRunnable输出:7
pool-1-thread-2 线程任务类MyRunnable输出:15
pool-1-thread-3 线程任务类MyRunnable输出:8
pool-1-thread-2 线程任务类MyRunnable输出:16
pool-1-thread-1 线程任务类MyRunnable输出:8
pool-1-thread-2 线程任务类MyRunnable输出:17
pool-1-thread-3 线程任务类MyRunnable输出:9
pool-1-thread-2 线程任务类MyRunnable输出:18
pool-1-thread-1 线程任务类MyRunnable输出:9
pool-1-thread-2 线程任务类MyRunnable输出:19
pool-1-thread-3 线程任务类MyRunnable输出:10
pool-1-thread-1 线程任务类MyRunnable输出:10
pool-1-thread-3 线程任务类MyRunnable输出:11
pool-1-thread-1 线程任务类MyRunnable输出:11
pool-1-thread-3 线程任务类MyRunnable输出:12
pool-1-thread-1 线程任务类MyRunnable输出:12
pool-1-thread-3 线程任务类MyRunnable输出:13
pool-1-thread-3 线程任务类MyRunnable输出:14
pool-1-thread-1 线程任务类MyRunnable输出:13
pool-1-thread-3 线程任务类MyRunnable输出:15
pool-1-thread-1 线程任务类MyRunnable输出:14
pool-1-thread-3 线程任务类MyRunnable输出:16
pool-1-thread-1 线程任务类MyRunnable输出:15
pool-1-thread-3 线程任务类MyRunnable输出:17
pool-1-thread-1 线程任务类MyRunnable输出:16
pool-1-thread-3 线程任务类MyRunnable输出:18
pool-1-thread-1 线程任务类MyRunnable输出:17
pool-1-thread-3 线程任务类MyRunnable输出:19
pool-1-thread-1 线程任务类MyRunnable输出:18
pool-1-thread-1 线程任务类MyRunnable输出:19
=========================pool-1-thread-2线程任务类MyRunnable执行完毕!=========================
=========================pool-1-thread-3线程任务类MyRunnable执行完毕!=========================
pool-1-thread-2 线程任务类MyRunnable输出:0
pool-1-thread-2 线程任务类MyRunnable输出:1
pool-1-thread-3 线程任务类MyRunnable输出:0
pool-1-thread-2 线程任务类MyRunnable输出:2
pool-1-thread-3 线程任务类MyRunnable输出:1
pool-1-thread-2 线程任务类MyRunnable输出:3
=========================pool-1-thread-1线程任务类MyRunnable执行完毕!=========================
pool-1-thread-1 线程任务类MyRunnable输出:0
pool-1-thread-2 线程任务类MyRunnable输出:4
pool-1-thread-3 线程任务类MyRunnable输出:2
pool-1-thread-2 线程任务类MyRunnable输出:5
pool-1-thread-1 线程任务类MyRunnable输出:1
pool-1-thread-1 线程任务类MyRunnable输出:2
pool-1-thread-2 线程任务类MyRunnable输出:6
pool-1-thread-3 线程任务类MyRunnable输出:3
pool-1-thread-2 线程任务类MyRunnable输出:7
pool-1-thread-1 线程任务类MyRunnable输出:3
pool-1-thread-1 线程任务类MyRunnable输出:4
pool-1-thread-2 线程任务类MyRunnable输出:8
pool-1-thread-2 线程任务类MyRunnable输出:9
pool-1-thread-3 线程任务类MyRunnable输出:4
pool-1-thread-2 线程任务类MyRunnable输出:10
pool-1-thread-1 线程任务类MyRunnable输出:5
pool-1-thread-1 线程任务类MyRunnable输出:6
pool-1-thread-2 线程任务类MyRunnable输出:11
pool-1-thread-2 线程任务类MyRunnable输出:12
pool-1-thread-3 线程任务类MyRunnable输出:5
pool-1-thread-2 线程任务类MyRunnable输出:13
pool-1-thread-1 线程任务类MyRunnable输出:7
pool-1-thread-1 线程任务类MyRunnable输出:8
pool-1-thread-2 线程任务类MyRunnable输出:14
pool-1-thread-3 线程任务类MyRunnable输出:6
pool-1-thread-2 线程任务类MyRunnable输出:15
pool-1-thread-1 线程任务类MyRunnable输出:9
pool-1-thread-2 线程任务类MyRunnable输出:16
pool-1-thread-3 线程任务类MyRunnable输出:7
pool-1-thread-2 线程任务类MyRunnable输出:17
pool-1-thread-1 线程任务类MyRunnable输出:10
pool-1-thread-2 线程任务类MyRunnable输出:18
pool-1-thread-3 线程任务类MyRunnable输出:8
pool-1-thread-2 线程任务类MyRunnable输出:19
pool-1-thread-1 线程任务类MyRunnable输出:11
=========================pool-1-thread-2线程任务类MyRunnable执行完毕!=========================
pool-1-thread-3 线程任务类MyRunnable输出:9
pool-1-thread-1 线程任务类MyRunnable输出:12
pool-1-thread-3 线程任务类MyRunnable输出:10
pool-1-thread-1 线程任务类MyRunnable输出:13
pool-1-thread-3 线程任务类MyRunnable输出:11
pool-1-thread-1 线程任务类MyRunnable输出:14
pool-1-thread-3 线程任务类MyRunnable输出:12
pool-1-thread-1 线程任务类MyRunnable输出:15
pool-1-thread-3 线程任务类MyRunnable输出:13
pool-1-thread-1 线程任务类MyRunnable输出:16
pool-1-thread-3 线程任务类MyRunnable输出:14
pool-1-thread-3 线程任务类MyRunnable输出:15
pool-1-thread-1 线程任务类MyRunnable输出:17
pool-1-thread-3 线程任务类MyRunnable输出:16
pool-1-thread-1 线程任务类MyRunnable输出:18
pool-1-thread-3 线程任务类MyRunnable输出:17
pool-1-thread-1 线程任务类MyRunnable输出:19
pool-1-thread-3 线程任务类MyRunnable输出:18
=========================pool-1-thread-1线程任务类MyRunnable执行完毕!=========================
pool-1-thread-3 线程任务类MyRunnable输出:19
=========================pool-1-thread-3线程任务类MyRunnable执行完毕!=========================

 

 

ExecutorServiceDemo2.java      线程池处理Callable任务

import java.util.concurrent.*;

/**
 * 参数一:corePoolSize:指定线程池的核心线程的数量
 * 参数二:maximumPoolSize:指定线程池的最大线程数量
 * 参数三:keepAliveTime:指定临时线程的存活时间
 * 参数四:unit:指定临时线程存活的时间单位(秒、分、时、天)
 * 参数五:workQueue:指定线程池的任务队列
 * 参数六:threadFactory:指定线程池的线程工厂
 * 参数七:handler:指定线程池的任务拒绝策略(线程都在忙,任务队列也满了的时候,新任务来了该怎么处理)
 */

/**
 * 临时线程创建条件:1.有定义临时线程的名额 2.核心线程都在工作
 *               3.任务队列满员 4.有新任务尝试加入任务队列
 * 什么时候拒绝新任务?
 *               核心线程和临时线程都在忙,新任务来了,就拒绝新任务。
 */

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

public class ExecutorServiceDemo2 {
    public static void main(String[] args) {
        //目标:创建线程池对象来使用。
        //1、使用线程池的实现类ThreadPoolExecutor声明七个参数来创建线程对象。
        ThreadPoolExecutor pool = new ThreadPoolExecutor(
                3,
                5,
                10,
                TimeUnit.SECONDS,//参数四:unit:指定临时线程存活的时间单位(秒、分、时、天)
                new ArrayBlockingQueue<>(3),//参数五:workQueue:指定线程池的任务队列
                Executors.defaultThreadFactory(),//参数六:threadFactory:指定线程池的线程工厂
                new ThreadPoolExecutor.AbortPolicy()//参数七:handler:指定线程池的任务拒绝策略
        );

        //2.使用线程池处理Callable任务
        Future<String> f1 = pool.submit(new MyCallable(20));
        Future<String> f2 = pool.submit(new MyCallable(21));
        Future<String> f3 = pool.submit(new MyCallable(22));
        Future<String> f4 = pool.submit(new MyCallable(23));
        Future<String> f5 = pool.submit(new MyCallable(24));

        try {
            System.out.println(f1.get());
            System.out.println(f2.get());
            System.out.println(f3.get());
            System.out.println(f4.get());
            System.out.println(f5.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

class MyCallable implements Callable<String> {
    private int n;
    public MyCallable(int n) { this.n = n; }
    //2.实现call方法,将线程要执行的代码放入call方法中。
    @Override
    public String call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= n; i++) {
            System.out.println(Thread.currentThread().getName() + " 子线程MyCallable 1-- " + n + " 的call方法输出:" + i);sum += i;
        }
        return "==============================" + Thread.currentThread().getName() + "子线程MyCallable 1-- " + n + " 的最终输出: " + sum + "==============================";
    }
}

res

pool-1-thread-1 子线程MyCallable 1-- 20 的call方法输出:1
pool-1-thread-2 子线程MyCallable 1-- 21 的call方法输出:1
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:1
pool-1-thread-2 子线程MyCallable 1-- 21 的call方法输出:2
pool-1-thread-1 子线程MyCallable 1-- 20 的call方法输出:2
pool-1-thread-2 子线程MyCallable 1-- 21 的call方法输出:3
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:2
pool-1-thread-2 子线程MyCallable 1-- 21 的call方法输出:4
pool-1-thread-1 子线程MyCallable 1-- 20 的call方法输出:3
pool-1-thread-2 子线程MyCallable 1-- 21 的call方法输出:5
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:3
pool-1-thread-2 子线程MyCallable 1-- 21 的call方法输出:6
pool-1-thread-1 子线程MyCallable 1-- 20 的call方法输出:4
pool-1-thread-2 子线程MyCallable 1-- 21 的call方法输出:7
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:4
pool-1-thread-2 子线程MyCallable 1-- 21 的call方法输出:8
pool-1-thread-1 子线程MyCallable 1-- 20 的call方法输出:5
pool-1-thread-2 子线程MyCallable 1-- 21 的call方法输出:9
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:5
pool-1-thread-2 子线程MyCallable 1-- 21 的call方法输出:10
pool-1-thread-1 子线程MyCallable 1-- 20 的call方法输出:6
pool-1-thread-2 子线程MyCallable 1-- 21 的call方法输出:11
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:6
pool-1-thread-2 子线程MyCallable 1-- 21 的call方法输出:12
pool-1-thread-1 子线程MyCallable 1-- 20 的call方法输出:7
pool-1-thread-2 子线程MyCallable 1-- 21 的call方法输出:13
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:7
pool-1-thread-2 子线程MyCallable 1-- 21 的call方法输出:14
pool-1-thread-1 子线程MyCallable 1-- 20 的call方法输出:8
pool-1-thread-2 子线程MyCallable 1-- 21 的call方法输出:15
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:8
pool-1-thread-2 子线程MyCallable 1-- 21 的call方法输出:16
pool-1-thread-1 子线程MyCallable 1-- 20 的call方法输出:9
pool-1-thread-2 子线程MyCallable 1-- 21 的call方法输出:17
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:9
pool-1-thread-2 子线程MyCallable 1-- 21 的call方法输出:18
pool-1-thread-1 子线程MyCallable 1-- 20 的call方法输出:10
pool-1-thread-2 子线程MyCallable 1-- 21 的call方法输出:19
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:10
pool-1-thread-2 子线程MyCallable 1-- 21 的call方法输出:20
pool-1-thread-1 子线程MyCallable 1-- 20 的call方法输出:11
pool-1-thread-1 子线程MyCallable 1-- 20 的call方法输出:12
pool-1-thread-2 子线程MyCallable 1-- 21 的call方法输出:21
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:11
pool-1-thread-1 子线程MyCallable 1-- 20 的call方法输出:13
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:12
pool-1-thread-1 子线程MyCallable 1-- 20 的call方法输出:14
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:13
pool-1-thread-1 子线程MyCallable 1-- 20 的call方法输出:15
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:14
pool-1-thread-1 子线程MyCallable 1-- 20 的call方法输出:16
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:15
pool-1-thread-1 子线程MyCallable 1-- 20 的call方法输出:17
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:16
pool-1-thread-1 子线程MyCallable 1-- 20 的call方法输出:18
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:17
pool-1-thread-1 子线程MyCallable 1-- 20 的call方法输出:19
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:18
pool-1-thread-1 子线程MyCallable 1-- 20 的call方法输出:20
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:19
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:20
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:21
pool-1-thread-3 子线程MyCallable 1-- 22 的call方法输出:22
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:1
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:2
==============================pool-1-thread-1子线程MyCallable 1-- 20 的最终输出: 210==============================
==============================pool-1-thread-2子线程MyCallable 1-- 21 的最终输出: 231==============================
==============================pool-1-thread-3子线程MyCallable 1-- 22 的最终输出: 253==============================
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:1
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:3
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:2
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:4
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:3
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:5
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:4
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:6
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:5
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:7
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:6
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:8
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:7
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:9
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:8
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:10
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:9
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:11
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:10
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:12
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:11
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:13
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:12
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:14
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:13
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:15
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:14
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:16
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:15
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:17
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:16
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:18
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:17
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:19
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:18
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:20
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:19
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:21
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:20
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:22
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:21
pool-1-thread-2 子线程MyCallable 1-- 23 的call方法输出:23
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:22
==============================pool-1-thread-2子线程MyCallable 1-- 23 的最终输出: 276==============================
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:23
pool-1-thread-1 子线程MyCallable 1-- 24 的call方法输出:24
==============================pool-1-thread-1子线程MyCallable 1-- 24 的最终输出: 300==============================

 

 

抢红包模拟      线程、线程安全、流打印

MyDemo1.java

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyDemo1 {
    public static RedBag[] rbs;
    public static void main(String[] args) {
        Employee[] emps = new Employee[100];
        for (int i = 0; i < 100; i++) {
            emps[i] = new Employee(i + 1, 0);
        }
        rbs = new RedBag[200];
        for (int i = 0; i < 40; i++) {
            // 生成[3100, 10000]的整数(包含两端)
            int randomInt = ThreadLocalRandom.current().nextInt(3100, 10001);
            // 转换为保留两位小数的double
            double randomValue = randomInt / 100.0;
            rbs[i] = new RedBag(randomValue);
        }
        for(int i = 40;i < 200;i++){
            // 生成[100, 3000]的整数(包含两端)
            int randomInt = ThreadLocalRandom.current().nextInt(100, 3001);
            // 转换为保留两位小数的double
            double randomValue = randomInt / 100.0;
            rbs[i] = new RedBag(randomValue);
        }
        //打乱数组rbs
        List<RedBag> redBagList = Arrays.asList(rbs);
        Collections.shuffle(redBagList);
        redBagList.toArray(rbs);//将 List 集合 redBagList 中的元素复制回数组 rbs 中

        // 创建并启动员工线程
        for (int i = 0; i < 100; i++) {
            new Thread(emps[i]).start();
        }

        // 等待所有线程执行完毕
        try {
            Thread.sleep(5000); // 假设活动持续 5 秒
            System.out.println("--------------------------活动结束--------------------------");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //使用流对员工抢到红包的金额进行降序排序打印
        Arrays.stream(emps)
                .sorted((e1, e2) -> Double.compare(e2.getIncome(), e1.getIncome()))
                .forEach(emp -> System.out.println("员工 " + emp.getId() + " 总收入:" + emp.getIncome()));

    }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class Employee implements Runnable{
    private int id;
    private double income;

    @Override
    public void run(){
        for (RedBag rb : MyDemo1.rbs) {
            if (rb.getMoney() > 0) {
                double received = receive(rb);
                if (received > 0) {
                    System.out.println("员工 " + id + " 抢到了红包 " + received + " 元,目前总共抢到 " + this.income + " 元");
                }
                try {
                    Thread.sleep(100); // 假设抢红包的间隔为 100 毫秒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public double receive(RedBag rb){
        if(rb.getMoney() == 0){
            return 0;
        }
        rb.getLk().lock();
        try{
            double amount = rb.getMoney();
            if(amount > 0){
                this.income += amount;
                rb.setMoney(0);
                return amount;
            }
        }finally {
            rb.getLk().unlock();
        }
        return 0;//只有红包金额为0时才在这里返回0
    }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class RedBag{
    private double money;
    private final Lock lk = new ReentrantLock();

    public double getMoney(){
        lk.lock();
        try {
            return money;
        } finally {
            lk.unlock();
        }
    }
}

 

res

员工 7 抢到了红包 8.6 元,目前总共抢到 8.6 元
员工 25 抢到了红包 5.94 元,目前总共抢到 5.94 元
员工 36 抢到了红包 43.84 元,目前总共抢到 43.84 元
员工 17 抢到了红包 48.18 元,目前总共抢到 48.18 元
员工 8 抢到了红包 16.5 元,目前总共抢到 16.5 元
员工 1 抢到了红包 29.92 元,目前总共抢到 29.92 元
员工 4 抢到了红包 18.81 元,目前总共抢到 18.81 元
员工 12 抢到了红包 14.58 元,目前总共抢到 14.58 元
员工 2 抢到了红包 6.72 元,目前总共抢到 6.72 元
员工 16 抢到了红包 6.51 元,目前总共抢到 6.51 元
员工 10 抢到了红包 18.98 元,目前总共抢到 18.98 元
员工 21 抢到了红包 45.24 元,目前总共抢到 45.24 元
员工 5 抢到了红包 94.27 元,目前总共抢到 94.27 元
员工 20 抢到了红包 28.9 元,目前总共抢到 28.9 元
员工 29 抢到了红包 2.37 元,目前总共抢到 2.37 元
员工 9 抢到了红包 16.55 元,目前总共抢到 16.55 元
员工 24 抢到了红包 39.85 元,目前总共抢到 39.85 元
员工 6 抢到了红包 1.03 元,目前总共抢到 1.03 元
员工 18 抢到了红包 10.68 元,目前总共抢到 10.68 元
员工 14 抢到了红包 2.54 元,目前总共抢到 2.54 元
员工 28 抢到了红包 12.36 元,目前总共抢到 12.36 元
员工 13 抢到了红包 16.74 元,目前总共抢到 16.74 元
员工 19 抢到了红包 98.01 元,目前总共抢到 98.01 元
员工 53 抢到了红包 8.14 元,目前总共抢到 8.14 元
员工 22 抢到了红包 25.18 元,目前总共抢到 25.18 元
员工 58 抢到了红包 12.87 元,目前总共抢到 12.87 元
员工 26 抢到了红包 27.95 元,目前总共抢到 27.95 元
员工 27 抢到了红包 15.82 元,目前总共抢到 15.82 元
员工 30 抢到了红包 27.3 元,目前总共抢到 27.3 元
员工 31 抢到了红包 36.06 元,目前总共抢到 36.06 元
员工 32 抢到了红包 14.25 元,目前总共抢到 14.25 元
员工 34 抢到了红包 12.86 元,目前总共抢到 12.86 元
员工 35 抢到了红包 61.72 元,目前总共抢到 61.72 元
员工 33 抢到了红包 4.39 元,目前总共抢到 4.39 元
员工 37 抢到了红包 15.06 元,目前总共抢到 15.06 元
员工 11 抢到了红包 12.11 元,目前总共抢到 12.11 元
员工 38 抢到了红包 1.23 元,目前总共抢到 1.23 元
员工 39 抢到了红包 16.05 元,目前总共抢到 16.05 元
员工 42 抢到了红包 29.86 元,目前总共抢到 29.86 元
员工 43 抢到了红包 22.22 元,目前总共抢到 22.22 元
员工 46 抢到了红包 9.45 元,目前总共抢到 9.45 元
员工 50 抢到了红包 3.89 元,目前总共抢到 3.89 元
员工 54 抢到了红包 29.1 元,目前总共抢到 29.1 元
员工 51 抢到了红包 26.16 元,目前总共抢到 26.16 元
员工 47 抢到了红包 16.35 元,目前总共抢到 16.35 元
员工 40 抢到了红包 23.44 元,目前总共抢到 23.44 元
员工 41 抢到了红包 62.45 元,目前总共抢到 62.45 元
员工 44 抢到了红包 40.36 元,目前总共抢到 40.36 元
员工 48 抢到了红包 27.99 元,目前总共抢到 27.99 元
员工 90 抢到了红包 10.16 元,目前总共抢到 10.16 元
员工 52 抢到了红包 16.89 元,目前总共抢到 16.89 元
员工 49 抢到了红包 26.46 元,目前总共抢到 26.46 元
员工 55 抢到了红包 60.89 元,目前总共抢到 60.89 元
员工 56 抢到了红包 12.86 元,目前总共抢到 12.86 元
员工 57 抢到了红包 4.77 元,目前总共抢到 4.77 元
员工 15 抢到了红包 21.16 元,目前总共抢到 21.16 元
员工 23 抢到了红包 7.27 元,目前总共抢到 7.27 元
员工 94 抢到了红包 5.09 元,目前总共抢到 5.09 元
员工 61 抢到了红包 15.7 元,目前总共抢到 15.7 元
员工 62 抢到了红包 24.6 元,目前总共抢到 24.6 元
员工 59 抢到了红包 80.89 元,目前总共抢到 80.89 元
员工 73 抢到了红包 7.24 元,目前总共抢到 7.24 元
员工 72 抢到了红包 7.75 元,目前总共抢到 7.75 元
员工 76 抢到了红包 14.05 元,目前总共抢到 14.05 元
员工 77 抢到了红包 8.77 元,目前总共抢到 8.77 元
员工 64 抢到了红包 2.38 元,目前总共抢到 2.38 元
员工 60 抢到了红包 15.85 元,目前总共抢到 15.85 元
员工 75 抢到了红包 25.03 元,目前总共抢到 25.03 元
员工 79 抢到了红包 2.27 元,目前总共抢到 2.27 元
员工 91 抢到了红包 4.45 元,目前总共抢到 4.45 元
员工 82 抢到了红包 14.08 元,目前总共抢到 14.08 元
员工 78 抢到了红包 9.21 元,目前总共抢到 9.21 元
员工 81 抢到了红包 3.18 元,目前总共抢到 3.18 元
员工 84 抢到了红包 8.05 元,目前总共抢到 8.05 元
员工 86 抢到了红包 55.15 元,目前总共抢到 55.15 元
员工 88 抢到了红包 68.5 元,目前总共抢到 68.5 元
员工 83 抢到了红包 94.85 元,目前总共抢到 94.85 元
员工 45 抢到了红包 18.12 元,目前总共抢到 18.12 元
员工 87 抢到了红包 15.33 元,目前总共抢到 15.33 元
员工 71 抢到了红包 6.39 元,目前总共抢到 6.39 元
员工 80 抢到了红包 11.51 元,目前总共抢到 11.51 元
员工 74 抢到了红包 6.52 元,目前总共抢到 6.52 元
员工 70 抢到了红包 50.44 元,目前总共抢到 50.44 元
员工 68 抢到了红包 4.17 元,目前总共抢到 4.17 元
员工 67 抢到了红包 26.86 元,目前总共抢到 26.86 元
员工 66 抢到了红包 25.4 元,目前总共抢到 25.4 元
员工 69 抢到了红包 26.94 元,目前总共抢到 26.94 元
员工 65 抢到了红包 14.93 元,目前总共抢到 14.93 元
员工 63 抢到了红包 12.07 元,目前总共抢到 12.07 元
员工 100 抢到了红包 9.48 元,目前总共抢到 9.48 元
员工 95 抢到了红包 24.56 元,目前总共抢到 24.56 元
员工 98 抢到了红包 51.81 元,目前总共抢到 51.81 元
员工 99 抢到了红包 14.57 元,目前总共抢到 14.57 元
员工 97 抢到了红包 39.59 元,目前总共抢到 39.59 元
员工 89 抢到了红包 12.18 元,目前总共抢到 12.18 元
员工 85 抢到了红包 12.97 元,目前总共抢到 12.97 元
员工 92 抢到了红包 9.06 元,目前总共抢到 9.06 元
员工 96 抢到了红包 8.23 元,目前总共抢到 8.23 元
员工 3 抢到了红包 19.35 元,目前总共抢到 19.35 元
员工 25 抢到了红包 21.91 元,目前总共抢到 27.85 元
员工 36 抢到了红包 3.17 元,目前总共抢到 47.010000000000005 元
员工 17 抢到了红包 19.7 元,目前总共抢到 67.88 元
员工 4 抢到了红包 36.61 元,目前总共抢到 55.42 元
员工 1 抢到了红包 75.88 元,目前总共抢到 105.8 元
员工 7 抢到了红包 28.07 元,目前总共抢到 36.67 元
员工 12 抢到了红包 11.26 元,目前总共抢到 25.84 元
员工 8 抢到了红包 42.99 元,目前总共抢到 59.49 元
员工 16 抢到了红包 27.12 元,目前总共抢到 33.63 元
员工 13 抢到了红包 28.01 元,目前总共抢到 44.75 元
员工 2 抢到了红包 26.99 元,目前总共抢到 33.71 元
员工 10 抢到了红包 70.07 元,目前总共抢到 89.05 元
员工 54 抢到了红包 13.73 元,目前总共抢到 42.83 元
员工 46 抢到了红包 15.3 元,目前总共抢到 24.75 元
员工 42 抢到了红包 9.52 元,目前总共抢到 39.379999999999995 元
员工 43 抢到了红包 10.09 元,目前总共抢到 32.31 元
员工 39 抢到了红包 16.46 元,目前总共抢到 32.510000000000005 元
员工 38 抢到了红包 17.94 元,目前总共抢到 19.17 元
员工 37 抢到了红包 67.96 元,目前总共抢到 83.02 元
员工 33 抢到了红包 10.76 元,目前总共抢到 15.149999999999999 元
员工 58 抢到了红包 15.95 元,目前总共抢到 28.82 元
员工 53 抢到了红包 7.3 元,目前总共抢到 15.440000000000001 元
员工 34 抢到了红包 20.09 元,目前总共抢到 32.95 元
员工 28 抢到了红包 77.88 元,目前总共抢到 90.24 元
员工 11 抢到了红包 27.6 元,目前总共抢到 39.71 元
员工 24 抢到了红包 3.6 元,目前总共抢到 43.45 元
员工 27 抢到了红包 26.54 元,目前总共抢到 42.36 元
员工 31 抢到了红包 38.28 元,目前总共抢到 74.34 元
员工 35 抢到了红包 57.8 元,目前总共抢到 119.52 元
员工 9 抢到了红包 13.39 元,目前总共抢到 29.94 元
员工 26 抢到了红包 16.35 元,目前总共抢到 44.3 元
员工 29 抢到了红包 10.83 元,目前总共抢到 13.2 元
员工 19 抢到了红包 82.76 元,目前总共抢到 180.77 元
员工 20 抢到了红包 20.75 元,目前总共抢到 49.65 元
员工 22 抢到了红包 20.74 元,目前总共抢到 45.92 元
员工 5 抢到了红包 33.21 元,目前总共抢到 127.47999999999999 元
员工 18 抢到了红包 8.04 元,目前总共抢到 18.72 元
员工 21 抢到了红包 45.31 元,目前总共抢到 90.55000000000001 元
员工 6 抢到了红包 2.93 元,目前总共抢到 3.96 元
员工 14 抢到了红包 68.75 元,目前总共抢到 71.29 元
员工 32 抢到了红包 19.8 元,目前总共抢到 34.05 元
员工 47 抢到了红包 11.86 元,目前总共抢到 28.21 元
员工 51 抢到了红包 27.91 元,目前总共抢到 54.07 元
员工 30 抢到了红包 22.93 元,目前总共抢到 50.230000000000004 元
员工 23 抢到了红包 15.76 元,目前总共抢到 23.03 元
员工 56 抢到了红包 21.74 元,目前总共抢到 34.599999999999994 元
员工 55 抢到了红包 28.26 元,目前总共抢到 89.15 元
员工 80 抢到了红包 5.42 元,目前总共抢到 16.93 元
员工 71 抢到了红包 24.15 元,目前总共抢到 30.54 元
员工 68 抢到了红包 18.82 元,目前总共抢到 22.990000000000002 元
员工 87 抢到了红包 23.1 元,目前总共抢到 38.43 元
员工 83 抢到了红包 78.39 元,目前总共抢到 173.24 元
员工 70 抢到了红包 28.31 元,目前总共抢到 78.75 元
员工 82 抢到了红包 66.97 元,目前总共抢到 81.05 元
员工 74 抢到了红包 14.39 元,目前总共抢到 20.91 元
员工 78 抢到了红包 17.74 元,目前总共抢到 26.95 元
员工 45 抢到了红包 12.8 元,目前总共抢到 30.92 元
员工 86 抢到了红包 70.14 元,目前总共抢到 125.28999999999999 元
员工 79 抢到了红包 29.96 元,目前总共抢到 32.230000000000004 元
员工 84 抢到了红包 19.87 元,目前总共抢到 27.92 元
员工 88 抢到了红包 50.53 元,目前总共抢到 119.03 元
员工 66 抢到了红包 12.42 元,目前总共抢到 37.82 元
员工 91 抢到了红包 7.19 元,目前总共抢到 11.64 元
员工 93 抢到了红包 3.98 元,目前总共抢到 3.98 元
员工 62 抢到了红包 1.38 元,目前总共抢到 25.98 元
员工 59 抢到了红包 13.81 元,目前总共抢到 94.7 元
员工 81 抢到了红包 13.05 元,目前总共抢到 16.23 元
员工 99 抢到了红包 21.59 元,目前总共抢到 36.16 元
员工 75 抢到了红包 38.93 元,目前总共抢到 63.96 元
员工 72 抢到了红包 14.71 元,目前总共抢到 22.46 元
员工 77 抢到了红包 10.23 元,目前总共抢到 19.0 元
员工 98 抢到了红包 1.76 元,目前总共抢到 53.57 元
员工 64 抢到了红包 28.78 元,目前总共抢到 31.16 元
员工 94 抢到了红包 34.82 元,目前总共抢到 39.91 元
员工 60 抢到了红包 23.95 元,目前总共抢到 39.8 元
员工 100 抢到了红包 16.86 元,目前总共抢到 26.34 元
员工 61 抢到了红包 6.17 元,目前总共抢到 21.869999999999997 元
员工 63 抢到了红包 12.29 元,目前总共抢到 24.36 元
员工 73 抢到了红包 20.63 元,目前总共抢到 27.869999999999997 元
员工 90 抢到了红包 8.58 元,目前总共抢到 18.740000000000002 元
员工 95 抢到了红包 19.57 元,目前总共抢到 44.129999999999995 元
员工 76 抢到了红包 22.78 元,目前总共抢到 36.83 元
员工 49 抢到了红包 11.33 元,目前总共抢到 37.79 元
员工 52 抢到了红包 29.05 元,目前总共抢到 45.94 元
员工 44 抢到了红包 12.57 元,目前总共抢到 52.93 元
员工 85 抢到了红包 76.85 元,目前总共抢到 89.82 元
员工 57 抢到了红包 2.12 元,目前总共抢到 6.89 元
员工 65 抢到了红包 3.45 元,目前总共抢到 18.38 元
员工 92 抢到了红包 14.49 元,目前总共抢到 23.55 元
员工 97 抢到了红包 5.86 元,目前总共抢到 45.45 元
员工 89 抢到了红包 15.11 元,目前总共抢到 27.29 元
员工 96 抢到了红包 57.1 元,目前总共抢到 65.33 元
员工 40 抢到了红包 13.94 元,目前总共抢到 37.38 元
员工 48 抢到了红包 10.17 元,目前总共抢到 38.16 元
员工 3 抢到了红包 6.86 元,目前总共抢到 26.21 元
员工 1 抢到了红包 91.66 元,目前总共抢到 197.45999999999998 元
员工 4 抢到了红包 4.52 元,目前总共抢到 59.94 元
员工 25 抢到了红包 12.8 元,目前总共抢到 40.650000000000006 元
员工 17 抢到了红包 28.87 元,目前总共抢到 96.75 元
员工 7 抢到了红包 90.62 元,目前总共抢到 127.29 元
员工 12 抢到了红包 13.45 元,目前总共抢到 39.29--------------------------活动结束--------------------------
员工 1 总收入:197.45999999999998
员工 19 总收入:180.77
员工 83 总收入:173.24
员工 5 总收入:127.47999999999999
员工 7 总收入:127.29
员工 86 总收入:125.28999999999999
员工 35 总收入:119.52
员工 88 总收入:119.03
员工 17 总收入:96.75
员工 59 总收入:94.7
员工 21 总收入:90.55000000000001
员工 28 总收入:90.24
员工 85 总收入:89.82
员工 55 总收入:89.15
员工 10 总收入:89.05
员工 37 总收入:83.02
员工 82 总收入:81.05
员工 70 总收入:78.75
员工 31 总收入:74.34
员工 14 总收入:71.29
员工 96 总收入:65.33
员工 75 总收入:63.96
员工 41 总收入:62.45
员工 4 总收入:59.94
员工 8 总收入:59.49
员工 51 总收入:54.07
员工 98 总收入:53.57
员工 44 总收入:52.93
员工 30 总收入:50.230000000000004
员工 20 总收入:49.65
员工 36 总收入:47.010000000000005
员工 52 总收入:45.94
员工 22 总收入:45.92
员工 97 总收入:45.45
员工 13 总收入:44.75
员工 26 总收入:44.3
员工 95 总收入:44.129999999999995
员工 24 总收入:43.45
员工 54 总收入:42.83
员工 27 总收入:42.36
员工 25 总收入:40.650000000000006
员工 94 总收入:39.91
员工 60 总收入:39.8
员工 11 总收入:39.71
员工 42 总收入:39.379999999999995
员工 12 总收入:39.29
员工 87 总收入:38.43
员工 48 总收入:38.16
员工 66 总收入:37.82
员工 49 总收入:37.79
员工 40 总收入:37.38
员工 76 总收入:36.83
员工 99 总收入:36.16
员工 56 总收入:34.599999999999994
员工 32 总收入:34.05
员工 2 总收入:33.71
员工 16 总收入:33.63
员工 34 总收入:32.95
员工 39 总收入:32.510000000000005
员工 43 总收入:32.31
员工 79 总收入:32.230000000000004
员工 64 总收入:31.16
员工 45 总收入:30.92
员工 71 总收入:30.54
员工 9 总收入:29.94
员工 58 总收入:28.82
员工 47 总收入:28.21
员工 84 总收入:27.92
员工 73 总收入:27.869999999999997
员工 89 总收入:27.29
员工 78 总收入:26.95
员工 69 总收入:26.94
员工 67 总收入:26.86
员工 100 总收入:26.34
员工 3 总收入:26.21
员工 62 总收入:25.98
员工 46 总收入:24.75
员工 63 总收入:24.36
员工 92 总收入:23.55
员工 23 总收入:23.03
员工 68 总收入:22.990000000000002
员工 72 总收入:22.46
员工 61 总收入:21.869999999999997
员工 15 总收入:21.16
员工 74 总收入:20.91
员工 38 总收入:19.17
员工 77 总收入:19.0
员工 90 总收入:18.740000000000002
员工 18 总收入:18.72
员工 65 总收入:18.38
员工 80 总收入:16.93
员工 81 总收入:16.23
员工 53 总收入:15.440000000000001
员工 33 总收入:15.149999999999999
员工 29 总收入:13.2
员工 91 总收入:11.64
员工 57 总收入:6.89
员工 93 总收入:3.98
员工 6 总收入:3.96
员工 50 总收入:3.89

 

posted on 2025-06-04 21:21  ᶜʸᵃⁿ  阅读(12)  评论(0)    收藏  举报