javaseday31多线程
什么是多线程
线程与进程
小结
并发和并行
并发
并行
小结
多线程的实现方式
方法一
public class Demo1 {
public static void main(String[] args) {
//使用多线程的第一种方法
/**
* 1、创建一个类继承Thread类
* 2、并重写run方法
* 3、创建子类对象,并启动线程
*/
MyThead m1= new MyThead();
MyThead m2= new MyThead();
//启动多线程不能使用对象直接调用run方法,需要调用start方法启动多线程
//给两个线程设置名字用以区分
m1.setName("线程1");
m2.setName("线程2");
m1.start();
m2.start();
/**
* 线程2helloworld
* 线程1helloworld
* 线程2helloworld
* 线程1helloworld
* 线程2helloworld
* 线程1helloworld
* 线程1helloworld
*/
}
}
public class MyThead extends Thread {
@Override
public void run() {
//重写run方法,getName()为创建对象时赋值给该对象的名字,用于表示执行的是哪个线程,getName()为父类中的方法
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"helloworld");
}
}
}
方法二
public class Demo2 {
public static void main(String[] args) {
/**
* 多线程的第二种方式
* 1、创建类实现Runnable接口
* 2、实现接口中的run方法
* 3、创建子类对象
* 4、将子类对象交给Thread线程对象进行操作
*/
//由于是将对象交给线程对象所以只需要一个子类对象
MyThread m1 = new MyThread();
//将这两个对象交给线程
Thread t1 = new Thread(m1);
Thread t2 = new Thread(m1);
//给两个线程对象赋值
t1.setName("线程一");
t2.setName("线程二");
//开启线程
t1.start();
t2.start();
}
}
public class MyThread implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
//调用线程方法获取当前执行的线程的对象
Thread thread = Thread.currentThread();
//获取线程对象的名字
System.out.println(thread.getName()+"halloWorld");
}
}
}
方法三:
public class Demo3 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
/**
* 多线程实现的第三种方式
* 特点:可以获取多线程运行的结果
* 1、创建一个类MyCallable实现Callable接口
* 2、重写call方法(有返回值,表示多线程的运行结果)
* 3、创建MyCallable对象(表示多线程执行的任务)
* 4、创建FutureTask的对象(用于管理多线程运行的结果)
* 5、创建Thread类的对象并启动(表示线程)
*
*/
//创建MyCallable对象(表示多线程执行的任务)
MyCallable myCallable = new MyCallable();
//创建FutureTask的对象(用于管理多线程运行的结果)
FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
//创建Thread类的对象并启动(表示线程)
Thread t = new Thread(futureTask);
//启动线程
t.start();
//获取线程运行的结果
Integer i = futureTask.get();
System.out.println(i);
}
}
public class MyCallable implements Callable<Integer> {
/*
Callable<Integer>的泛型表示返回值的类型
*/
@Override
public Integer call() throws Exception {
//求1-100之间的额值
int sum = 0;
for (int i = 0; i <= 100; i++) {
sum =sum +i;
}
return sum;
}
}
三种实现方法的对比
常见的成员方法
public class Demo1 {
public static void main(String[] args) {
/*
String getName() 返回此线程的名称
void setName(String name) 设置线程的名字(构造方法也可以设置名字)
细节:
1、如果我们没有给线程设置名字,线程也是有默认的名字的
格式:Thread-X(X序号,从0开始的)
2、如果我们要给线程设置名字,可以用set方法进行设置,也可以构造方法设置
static Thread currentThread() 获取当前线程的对象
细节:
当JVM虚拟机启动之后,会自动的启动多条线程
其中有一条线程就叫做main线程
他的作用就是去调用main方法,并执行里面的代码
在以前,我们写的所有的代码,其实都是运行在main线程当中
static void sleep(long time) 让线程休眠指定的时间,单位为毫秒
细节:
1、哪条线程执行到这个方法,那么哪条线程就会在这里停留对应的时间
2、方法的参数:就表示睡眠的时间,单位毫秒
1 秒= 1000毫秒
3、当时间到了之后,线程会自动的醒来,继续执行下面的其他代码
*/
//1.创建线程的对象
MyThead t1 = new MyThead("飞机");
MyThead t2 = new MyThead("坦克");
//2.开启线程
t1.start();
t2.start();
//哪条线程执行到这个方法,此时获取的就是哪条线程的对象
/* Thread t = Thread.currentThread();
String name = t.getName();
System.out.println(name);//main*/
/*System.out.println("11111111111");
//线程停止5秒钟
Thread.sleep(5000);
System.out.println("22222222222");*/
}
}
public class MyThead extends Thread {
//重写父类的部分构造方法
public MyThead() {
}
//重写父类中给线程赋值名字的构造方法
public MyThead(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
//线程的休眠,每次执行都会使线程休眠1秒钟
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//getName()表示线程的名字,如果没有赋值则使用默认的线程名,Thread+线程序号,从0开始
System.out.println(getName() + "@" + i);
}
}
}
第二组成员方法
public class Demo2 {
public static void main(String[] args) {
//线程的优先级
//创建线程
MyThead m1 = new MyThead();
Thread t1 = new Thread(m1,"坦克");
Thread t2 = new Thread(m1,"飞机");
//设置两个线程的优先级,最高位10最低位1,优先级为10不一定必定发生,优先级为1不一定不发生,这只是概率不同
t1.setPriority(10);
t2.setPriority(1);
t1.start();
t2.start();
//获取main方法的优先级,5
// System.out.println(Thread.currentThread().getPriority());
}
}
public class MyThead extends Thread {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "---" + i);
}
}
}
守护线程
public class Demo3 {
public static void main(String[] args) {
//备胎线程
/**
* 当其他线程结束时,备胎线程也会陆续结束(不一定是立即结束,但即使还没有运行完备胎线程,当其他进程结束时备胎线程也会结束)
*
*/
Threadgril tg = new Threadgril();
Threadman tm = new Threadman();
tg.setName("女神");
tm.setName("备胎");
//将tm线程设置为备胎线程
tm.setDaemon(true);
//启动两个线程
tg.start();
tm.start();
/**
* 女神女神进程9
* 备胎备胎进程16
* 备胎备胎进程17
* 备胎备胎进程18
* 备胎备胎进程19
* 备胎备胎进程20
* 女神线程结束时,备胎线程也陆续结束,且备胎线程没有完成
*/
}
}
public class Threadgril extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName()+"女神线程"+i);
}
}
}
public class Threadman extends Thread{
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"备胎线程"+i);
}
}
}
礼让线程(出让线程)
public class Demo4 {
public static void main(String[] args) {
/**
* 礼让线程
*礼让线程可以让线程的执行更加平均但是无法保证绝对的平均
*/
//1.创建线程的对象
threadmy t1 = new threadmy();
threadmy t2 = new threadmy();
//给线程赋名字
t1.setName("飞机");
t2.setName("坦克");
//2.开启线程
t1.start();
t2.start();
}
}
public class threadmy extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"="+i);
//表示让出当前CPU的执行权
Thread.yield();
}
}
}
插入线程
public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
/*
public final void join() 插入线程/插队线程
*/
MyThread t = new MyThread();
t.setName("土豆");
t.start();
//表示把t这个线程,插入到当前线程之前。
//当前线程为main线程,即插入到main线程之前,t线程结束后main线程才会执行
//t:土豆
//当前线程: main线程
t.join();
//执行在main线程当中的
for (int i = 0; i < 10; i++) {
System.out.println("main线程" + i);
}
}
}
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(getName() + "@" + i);
}
}
}
线程的生命周期
线程安全
练习
public class Demo5 {
public static void main(String[] args) {
/**
* 售票窗口有三个,可以看做三个线程
* 当前代码有问题,一张票会被收买多次,且有超出100的情况
* 窗口2窗口卖出的第100票
* 窗口3窗口卖出的第101票
* 窗口1窗口卖出的第102票
* 窗口2窗口卖出的第2票
* 窗口3窗口卖出的第2票
* 窗口1窗口卖出的第2票
*/
Mythread m1 = new Mythread();
Mythread m2 = new Mythread();
Mythread m3 = new Mythread();
m1.setName("窗口1");
m2.setName("窗口2");
m3.setName("窗口3");
m1.start();
m2.start();
m3.start();
}
}
public class Mythread extends Thread{
/**
* 售票的窗口为线程
*/
//设置静态变量记录售出的票数
static int tacket = 0;
@Override
public void run() {
while (true) {
//当有线程执行时
if (tacket<100){
//每次停止0.1秒
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
tacket++;
System.out.println(getName()+"窗口卖出的第"+tacket+"票");
}else {
break;
}
}
}
}
同步代码块
同步代码块修改过后的买票窗口
public class Mythread extends Thread{
/**
* 售票的窗口为线程
*/
//设置静态变量记录售出的票数
static int tacket = 0;
//锁对象可以是任意对象,但是一定要是唯一的,使用static静态变量修饰符
static Object obj = new Object();
@Override
public void run() {
while (true) {
//同步代码块
synchronized (obj){
//当有线程执行时
if (tacket<100){
//每次停止0.1秒
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
tacket++;
System.out.println(getName()+"窗口卖出的第"+tacket+"票");
}else {
break;
}
}
}
}
}
小细节
- synchronized一定要在循环里面,如果在外面就会导致所用的循环都有一个线程执行
- 锁对象一定要唯一。不为一就相当于没有锁。可以使用该类的类对象即class对象,应为这个只能有一个如
Mythread.class
public class Mythread extends Thread{
/**
* 售票的窗口为线程
*/
//设置静态变量记录售出的票数
static int tacket = 0;
//锁对象可以是任意对象,但是一定要是唯一的,使用static静态变量修饰符
static Object obj = new Object();
@Override
public void run() {
while (true) {
//同步代码块
synchronized (Mythread.class){
//当有线程执行时
if (tacket<100){
//每次停止0.1秒
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
tacket++;
System.out.println(getName()+"窗口卖出的第"+tacket+"票");
}else {
break;
}
}
}
}
}
同步方法
public class Demo5 {
public static void main(String[] args) {
methodthread mt = new methodthread();
Thread t1 = new Thread(mt);
Thread t2 = new Thread(mt);
Thread t3 = new Thread(mt);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
public class methodthread implements Runnable{
int tacket = 0;
@Override
public void run() {
while (true){
if (method()) break;
}
}
private synchronized boolean method() {
if (tacket == 100){
return true;
}else {
//使用同步代码块写在转换为同步方法
tacket++;
System.out.println(Thread.currentThread().getName()+"售卖了第"+tacket+"张票");
}
return false;
}
}
Lock锁
public class Demo4 {
public static void main(String[] args) {
//1.创建线程的对象
threadmy t1 = new threadmy();
threadmy t2 = new threadmy();
threadmy t3 = new threadmy();
//给线程赋名字
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
//2.开启线程
t1.start();
t2.start();
t3.start();
}
}
public class threadmy extends Thread {
/**
* 售票的窗口为线程
*/
//设置静态变量记录售出的票数
static int tacket = 0;
//lock锁
//由于Lock是接口所以要使用他的实现类
//static保证其只有一个
static Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
//加锁
lock.lock();
try {
//当有线程执行时
if (tacket < 100) {
//每次停止0.1秒
Thread.sleep(100);
tacket++;
System.out.println(getName() + "窗口卖出的第" + tacket + "票");
} else {
break;
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
//将其放入finally中保证其无论如何都可被执行
lock.unlock();
}
}
}
}
死锁(是一个错误)
public class MyThread extends Thread {
static Object objA = new Object();
static Object objB = new Object();
@Override
public void run() {
//1.循环
while (true) {
if ("线程A".equals(getName())) {
synchronized (objA) {
System.out.println("线程A拿到了A锁,准备拿B锁");//A
synchronized (objB) {
System.out.println("线程A拿到了B锁,顺利执行完一轮");
}
}
} else if ("线程B".equals(getName())) {
if ("线程B".equals(getName())) {
synchronized (objB) {
System.out.println("线程B拿到了B锁,准备拿A锁");//B
synchronized (objA) {
System.out.println("线程B拿到了A锁,顺利执行完一轮");
}
}
}
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
/*
需求:
死锁
*/
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.setName("线程A");
t2.setName("线程B");
t1.start();
t2.start();
}
}
等待唤醒机制(生产者和消费者)
常见方法
public class Test {
public static void main(String[] args) {
fooder f = new fooder();
cook c = new cook();
f.setName("吃货");
c.setName("厨师");
f.start();
c.start();
}
}
package MyThead.foodwork;
public class fooder extends Thread {
//消费者
/**
* 1、循还
* 2、同步代码块
* 3、判断共享数据是否到末尾
* 4、判断共享数据是否到末尾(没有,执行核心逻辑)
*/
@Override
public void run() {
while (true) {
synchronized (desk.lock) {
if (desk.count == 0) {
//应该停止
break;
} else {
/**
* 1、判断桌上是否有食物
* 2、有则吃
* 3、没有则等待
* 4、吃完后唤醒厨师
* 5、吃的总数-1
* 6、修改桌子的数据
*/
if (desk.foodFlag == 0) {
//使用锁对象调用是为了唤醒的时后进行精确唤醒
try {
desk.lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
} else {
//有实物
//吃的总数-1
desk.count = desk.count - 1;
//开始吃
System.out.println(getName() + "开始吃了,还能在吃" + desk.count + "碗");
//修改桌子的数据
desk.foodFlag = 0;
//吃完后唤醒厨师
desk.lock.notifyAll();
}
}
}
}
}
}
package MyThead.foodwork;
public class cook extends Thread {
//生产者
@Override
public void run() {
/**
* 1、循还
* 2、同步代码块
* 3、判断共享数据是否到末尾
* 4、判断共享数据是否到末尾(没有,执行核心逻辑)
*/
while (true) {
synchronized (desk.lock) {
if (desk.count == 0) {
//应该停止
break;
} else {
/**
* 1、判断桌上是否有食物
* 2、有则吃等待
* 3、没有则做
* 4、吃做后唤醒顾客
* 5、修改桌子的数据
*/
if (desk.foodFlag == 1) {
//使用锁对象调用是为了唤醒的时后进行精确唤醒
try {
desk.lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
} else {
//无实物
//开始做
System.out.println(getName() + "开始做");
//修改桌子的数据
desk.foodFlag = 1;
//吃完后唤醒顾客
desk.lock.notifyAll();
}
}
}
}
}
}
package MyThead.foodwork;
public class desk {
//桌子
//有没有食物
//有食物则吃货执行
public static int foodFlag = 0;
//加锁
public static Object lock = new Object();
//总的执行的个数
public static int count = 10;
}
阻塞队列实现等待唤醒机制
public class Tes {
public static void main(String[] args) {
//阻塞队列,ArrayBlockingQueue<>(1)表示队列只有一个位置
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);
Cook c = new Cook(queue);
Fooder f = new Fooder(queue);
c.start();
f.start();
}
}
public class Cook extends Thread{
//使用构造方法给阻塞队列赋初值保证两个线程使用同一个阻塞队列
ArrayBlockingQueue<String> queue;
public Cook(ArrayBlockingQueue<String> queue) {
this.queue = queue;
}
@Override
public void run() {
while (true){
try {
queue.put("面条");
System.out.println("厨师做了一碗面条");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class Fooder extends Thread{
//使用构造方法给阻塞队列赋初值保证两个线程使用同一个阻塞队列
ArrayBlockingQueue<String> queue;
public Fooder(ArrayBlockingQueue<String> queue) {
this.queue = queue;
}
@Override
public void run() {
while (true) {
String take = null;
try {
take = queue.take();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("食客吃了一碗"+take);
}
}
}
线程的状态
综合练习
练习一
public class threadmy extends Thread{
//票数共1000张
static int tacket = 1000;
//加一个锁对象
static Lock lock = new ReentrantLock();
@Override
public void run() {
while (true){
try {
lock.lock();
//判断有没有票
if (tacket == 0){
//没有票
break;
}else {
Thread.sleep(3000);
//有票
tacket --;
System.out.println("这是"+getName()+"售卖的票,当前是第"+(1000-tacket)+"张票");
System.out.println("还剩余"+tacket+"张票");
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
//保证无论如何都会打开锁
lock.unlock();
}
}
}
}
public class Test {
public static void main(String[] args) {
threadmy t1 = new threadmy();
threadmy t2 = new threadmy();
t1.setName("窗口1");
t2.setName("窗口2");
t1.start();
t2.start();
}
}
练习二
public class Test {
public static void main(String[] args) {
threadmy t1 = new threadmy();
threadmy t2 = new threadmy();
t1.setName("人1");
t2.setName("人2");
t1.start();
t2.start();
}
}
public class threadmy extends Thread{
//礼品共100份
static int tacket = 100;
//加一个锁对象
static Lock lock = new ReentrantLock();
@Override
public void run() {
while (true){
try {
lock.lock();
//判断礼品数量是否小于10
if (tacket <= 10){
//礼品数量小于10
break;
}else {
//间隔30毫秒
Thread.sleep(30);
//有礼物
tacket --;
System.out.println("这是"+getName()+"送的礼物,还剩余"+tacket+"个礼物");
System.out.println();
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
//保证无论如何都会打开锁
lock.unlock();
}
}
}
}
练习三
public class threadTest3 extends Thread{
static int num = 0;
//锁
Lock lock = new ReentrantLock();
public void run() {
while (true) {
synchronized (threadTest3.class) { // 使用类级别锁
if (num > 100) {
break;
}
// 判断是奇数
if (num % 2 != 0) {
System.out.println(getName() + "这个数是奇数:" + num);
}
num++; // 增加 num
}
}
}
//会出现两个1
// public void run() {
// while (true){
// lock.lock();
// try {
// //判断当前的数量
// if (num>100){
// break;
// }else {
// //判断是奇数还是偶数
// if (num%2==0){
// //偶数不进行处理
// }else {
// System.out.println(getName()+"这个数是奇数:"+num);
// }
// }
// num++;
// } catch (Exception e) {
// throw new RuntimeException(e);
// } finally {
// lock.unlock();
// }
// }
// }
}
public class Test3 {
public static void main(String[] args) {
threadTest3 t1 = new threadTest3();
threadTest3 t2 = new threadTest3();
t1.setName("线程一");
t2.setName("线程二");
t1.start();
t2.start();
}
}
练习四
public class threadTest4 extends Thread{
//抢红包
//总共的100元
static int m = 100;
//剩余红包数量
static int num = 3;
//抢红包的人数
static int j = 5;
//锁
static Lock lock = new ReentrantLock();
@Override
public void run() {
while (true){
//将进入的进程都进行休眠以保证在这个周期中每个线程都可以运行一次
try {
Thread.sleep(30);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
lock.lock();
try {
if (j==0){
break;
}else {
j--;
}
//判断还有没有红包
if (num == 0){
System.out.println(getName()+"没有抢到红包");
} else if (num==1) {
//最后一个红包,全部给这个人
System.out.println(getName()+"抢到了"+m+"元");
//修改数据
m = 0;
num = 0;
}else {
//其他情况
Random r = new Random();
//随机抢的钱数
int i = r.nextInt(m);
System.out.println(getName()+"抢到了"+i+"元");
//修改数据
m = m - i;
num--;
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
}
}
public class Test4 {
public static void main(String[] args) {
threadTest4 t1 = new threadTest4();
threadTest4 t2 = new threadTest4();
threadTest4 t3 = new threadTest4();
threadTest4 t4 = new threadTest4();
threadTest4 t5 = new threadTest4();
t1.setName("人一");
t2.setName("人二");
t3.setName("人三");
t4.setName("人四");
t5.setName("人五");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
讲一
public class Test4_2 {
public static void main(String[] args) {
thread2 t1 = new thread2();
thread2 t2 = new thread2();
thread2 t3 = new thread2();
thread2 t4 = new thread2();
thread2 t5 = new thread2();
t1.setName("人一");
t2.setName("人二");
t3.setName("人三");
t4.setName("人四");
t5.setName("人五");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
public class thread2 extends Thread{
//红包的个数
static int num = 3;
//红包的总金额
static double mon = 100;
//红包的最小金额
static final double MIN = 0.01;
@Override
public void run() {
Random r = new Random();
//每个线程执行一次不需要循化
synchronized (thread2.class){
//判断是否还有红包
if (num==0){
System.out.println(getName()+"没领到红包");
}else {
double price;
//判断是否是最后一个红包
if (num==1){
//将剩余的钱都放入这个红包
price = mon;
}else {
//随机红包的金额
//红包的限制
double n = mon - (num-1)*MIN;
double v = r.nextDouble(n);
price = v;
//如果小于最小值则强转变为最小值
if(price < MIN){
price = MIN;
}
}
mon = mon - price;
num--;
System.out.println(getName()+"抢到了红包 "+price+"元");
}
}
}
}
讲二(保留2位小数)
/**
* 由于小数随机导致数据出现小数点后多位,使用BigDecimal来避免这种情况
*/
public class thread3 extends Thread{
//红包的个数
static int num = 3;
//红包的总金额
static BigDecimal m = BigDecimal.valueOf(100);
//红包的最小金额
static final BigDecimal MIN = BigDecimal.valueOf(0.01);
@Override
public void run() {
Random r = new Random();
//每个线程执行一次不需要循化
synchronized (thread3.class){
//判断是否还有红包
if (num==0){
System.out.println(getName()+"没领到红包");
}else {
BigDecimal price;
//判断是否是最后一个红包
if (num==1){
//将剩余的钱都放入这个红包
price = m;
}else {
//随机红包的金额
//红包的限制
BigDecimal minn = MIN.multiply(BigDecimal.valueOf(num-1));
BigDecimal n = m.subtract(minn);
BigDecimal v = BigDecimal.valueOf(r.nextDouble(n.doubleValue()));
price = v;
//如果小于最小值则强转变为最小值
price = price.max(MIN);
// if(price < MIN){
// price = MIN;
// }
}
m = m.subtract(price);
num--;
System.out.println(getName()+"抢到了红包 "+formatToNumber(price)+"元");
}
}
}
/**
* @desc 1.0~1之间的BigDecimal小数,格式化后失去前面的0,则前面直接加上0。
* 2.传入的参数等于0,则直接返回字符串"0.00"
* 3.大于1的小数,直接格式化返回字符串
* @param
* @return
*/
public static String formatToNumber(BigDecimal obj) {
DecimalFormat df = new DecimalFormat("#.00");
if(obj.compareTo(BigDecimal.ZERO)==0) {
return "0.00";
}else if(obj.compareTo(BigDecimal.ZERO)>0&&obj.compareTo(new BigDecimal(1))<0){
return "0"+df.format(obj).toString();
}else {
return df.format(obj).toString();
}
}
}
public class Test4_3 {
public static void main(String[] args) {
thread3 t1 = new thread3();
thread3 t2 = new thread3();
thread3 t3 = new thread3();
thread3 t4 = new thread3();
thread3 t5 = new thread3();
t1.setName("人一");
t2.setName("人二");
t3.setName("人三");
t4.setName("人四");
t5.setName("人五");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
练习五
public class threadTest5 extends Thread{
//创建一个静态的奖池
static ArrayList<Integer> list = new ArrayList<>();
//给静态奖池赋值
static {
Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
}
//锁
static Lock lock = new ReentrantLock();
@Override
public void run() {
Random r = new Random();
while (true){
// //使抽奖更加均衡
try {
Thread.sleep(30);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//上锁
lock.lock();
try {
//判断奖池中是否还有数据
if (list.size()==0){
break;
}else {
//定义随机数抽取数据
int i = r.nextInt(list.size());
//将数据打印
System.out.println(getName()+" 又产生了一个 "+list.get(i)+" 元大奖");
//在list中删除该数据
list.remove(i);
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
}
}
public class Test5 {
public static void main(String[] args) {
threadTest5 t1 = new threadTest5();
threadTest5 t2 = new threadTest5();
t1.setName("抽奖箱一");
t2.setName("抽奖箱二");
t1.start();
t2.start();
}
}
练习六
public class threadTest6 extends Thread{
//创建一个静态的奖池
static ArrayList<Integer> list = new ArrayList<>();
//给静态奖池赋值
static {
Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
}
//用于存储每个线程的获取的数据
ArrayList<Integer> arr = new ArrayList<>();
//锁
static Lock lock = new ReentrantLock();
@Override
public void run() {
Random r = new Random();
while (true){
// //使抽奖更加均衡
try {
Thread.sleep(30);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//上锁
lock.lock();
try {
//判断奖池中是否还有数据
if (list.size()==0){
break;
}else {
//定义随机数抽取数据
int i = r.nextInt(list.size());
//将数据打印
// System.out.println(getName()+" 又产生了一个 "+list.get(i)+" 元大奖");
arr.add(list.get(i));
//在list中删除该数据
list.remove(i);
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
lock.lock();
try {
//执行完后调用输出
// System.out.println(getName()+arr.toString());
//整理各个线程的数据
getdata(arr);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
private void getdata(ArrayList<Integer> arr) {
System.out.println("在本次抽奖时,"+getName()+"共产生了"+arr.size()+"个奖项");
System.out.print("分别为");
for (int i = 0; i < arr.size(); i++) {
if (i == arr.size()-1){
System.out.print(arr.get(i));
}else {
System.out.print(arr.get(i)+", ");
}
}
int max = arr.get(0);
int sum = 0;
for (int i = 0; i < arr.size(); i++) {
sum = sum+arr.get(i);
if (arr.get(i)>max){
max = arr.get(i);
}
}
System.out.println("最高金额为"+max+"元,总金额为"+sum+"元");
}
}
public class Test6 {
public static void main(String[] args) {
threadTest6 t1 = new threadTest6();
threadTest6 t2 = new threadTest6();
t1.setName("抽奖箱一");
t2.setName("抽奖箱二");
t1.start();
t2.start();
}
}
练习七
public class threadTest7 extends Thread{
//创建一个静态的奖池
static ArrayList<Integer> list = new ArrayList<>();
//给静态奖池赋值
static {
Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
}
//用于存储每个线程的获取的数据
ArrayList<Integer> arr = new ArrayList<>();
//锁
static Lock lock = new ReentrantLock();
@Override
public void run() {
Random r = new Random();
while (true){
// //使抽奖更加均衡
try {
Thread.sleep(30);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//上锁
lock.lock();
try {
//判断奖池中是否还有数据
if (list.size()==0){
break;
}else {
//定义随机数抽取数据
int i = r.nextInt(list.size());
//将数据打印
// System.out.println(getName()+" 又产生了一个 "+list.get(i)+" 元大奖");
arr.add(list.get(i));
//在list中删除该数据
list.remove(i);
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
lock.lock();
try {
//执行完后调用输出
// System.out.println(getName()+arr.toString());
//整理各个线程的数据
getdata(arr);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
public ArrayList<Integer> data(){
return arr;
}
private void getdata(ArrayList<Integer> arr) {
System.out.println("在本次抽奖时,"+getName()+"共产生了"+arr.size()+"个奖项");
System.out.print("分别为");
for (int i = 0; i < arr.size(); i++) {
if (i == arr.size()-1){
System.out.print(arr.get(i));
}else {
System.out.print(arr.get(i)+", ");
}
}
int max = arr.get(0);
int sum = 0;
for (int i = 0; i < arr.size(); i++) {
sum = sum+arr.get(i);
if (arr.get(i)>max){
max = arr.get(i);
}
}
System.out.println("最高金额为"+max+"元,总金额为"+sum+"元");
}
}
public class Test7 {
public static void main(String[] args) throws InterruptedException {
threadTest7 t1 = new threadTest7();
threadTest7 t2 = new threadTest7();
t1.setName("抽奖箱一");
t2.setName("抽奖箱二");
t1.start();
t2.start();
//将这两个线程插入main线程之前,即只有这两个线程执行完毕,数据集合中有数据了在执行下面的data方法
t1.join();
t2.join();
ArrayList<Integer> data1 = t1.data();
ArrayList<Integer> data2 = t2.data();
//处理数据
//获取各种的最大值
int max1 = data1.get(0);
int max2 = data2.get(0);
for (Integer i : data1) {
if (i>max1){
max1 = i;
}
}
for (Integer i : data2) {
if (i>max2){
max2 = i;
}
}
//比较两个最大值
if (max1>max2){
System.out.println("本次抽奖中,"+t1.getName()+"获取最大奖项,该奖项金额为"+max1);
}else {
System.out.println("本次抽奖中,"+t2.getName()+"获取最大奖项,该奖项金额为"+max2);
}
//
// System.out.println(data1.toString());
// System.out.println(data2.toString());
}
}
讲解方法
public class Test7_2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
thread7_2 t1 = new thread7_2();
thread7_2 t2 = new thread7_2();
//创建FutureTask的对象(用于管理多线程运行的结果)
FutureTask<Integer> futureTask1 = new FutureTask<>(t1);
FutureTask<Integer> futureTask2 = new FutureTask<>(t2);
Thread th1 = new Thread(futureTask1);
Thread th2 = new Thread(futureTask2);
th1.setName("抽奖箱一");
th2.setName("抽奖箱二");
th1.start();
th2.start();
Integer i1 = futureTask1.get();
Integer i2 = futureTask2.get();
System.out.println("=====================");
System.out.println(i1);
System.out.println(i2);
if (i1>i2){
System.out.println(th1.getName()+"有最大金额"+i1);
}else {
System.out.println(th2.getName()+"有最大金额"+i2);
}
}
}
public class thread7_2 implements Callable<Integer> {
//创建一个静态的奖池
static ArrayList<Integer> list = new ArrayList<>();
//给静态奖池赋值
static {
Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
}
@Override
public Integer call() throws Exception {
//用于存储每个线程的获取的数据
ArrayList<Integer> arr = new ArrayList<>();
Random r = new Random();
while (true){
synchronized (thread7_2.class){
//判断奖池中是否还有数据
if (list.size()==0){
break;
}else {
//定义随机数抽取数据
int i = r.nextInt(list.size());
//将数据打印
// System.out.println(getName()+" 又产生了一个 "+list.get(i)+" 元大奖");
arr.add(list.get(i));
//在list中删除该数据
list.remove(i);
}
}
}
synchronized (thread7_2.class){
getdata(arr);
}
return Collections.max(arr);
}
private void getdata(ArrayList<Integer> arr) {
System.out.println("在本次抽奖时,"+Thread.currentThread().getName()+"共产生了"+arr.size()+"个奖项");
System.out.print("分别为");
for (int i = 0; i < arr.size(); i++) {
if (i == arr.size()-1){
System.out.print(arr.get(i));
}else {
System.out.print(arr.get(i)+", ");
}
}
int max = arr.get(0);
int sum = 0;
for (int i = 0; i < arr.size(); i++) {
sum = sum+arr.get(i);
if (arr.get(i)>max){
max = arr.get(i);
}
}
System.out.println("最高金额为"+max+"元,总金额为"+sum+"元");
}
}
练习八
线程池
之前多线程代码的弊端
线程池
实现
public class Test {
public static void main(String[] args) {
//创建一个线程池对象
// ExecutorService exe = Executors.newCachedThreadPool();
//限制线程的数量为三,超出的任务只能等待
ExecutorService exe = Executors.newFixedThreadPool(3);
//向线程池对象中提交任务
exe.submit(new threaddemo1());
exe.submit(new threaddemo1());
exe.submit(new threaddemo1());
exe.submit(new threaddemo1());
exe.submit(new threaddemo1());
//销毁线程池
exe.shutdown();
}
}
public class threaddemo1 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"===="+i);
}
}
}
自定义线程池
public class MyThreadPoolDemo1 {
public static void main(String[] args){
/*
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor
(核心线程数量,最大线程数量,空闲线程最大存活时间,任务队列,创建线程工厂,任务的拒绝策略);
参数一:核心线程数量 不能小于0
参数二:最大线程数 不能小于0,最大数量 >= 核心线程数量
参数三:空闲线程最大存活时间 不能小于0
参数四:时间单位 用TimeUnit指定
参数五:任务队列 不能为null
参数六:创建线程工厂 不能为null
参数七:任务的拒绝策略 不能为null
*/
ThreadPoolExecutor pool = new ThreadPoolExecutor(
3, //核心线程数量,能小于0
6, //最大线程数,不能小于0,最大数量 >= 核心线程数量
60,//空闲线程最大存活时间
TimeUnit.SECONDS,//时间单位
new ArrayBlockingQueue<>(3),//任务队列
Executors.defaultThreadFactory(),//创建线程工厂
new ThreadPoolExecutor.AbortPolicy()//任务的拒绝策略
);
}
}
线程池的最大
最大并行数
8即是最大并行数,