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