练习1
package lx1;
/*一共有1000张电影票,可以在两个窗口领取,假设每次领取的时间为3000毫秒,
要求:请用多线程模拟卖票过程并打印剩余电影票的数量*/
public class MyThread extends Thread {
static int ticket = 1000;//多个线程对象共享同一个电影票
//第一种方式实现多线程,测试类中MyThread会创建多次,所以需要加stat
@Override
public void run() {
//1.循环
while (true) {
//2.同步代码块
synchronized (MyThread.class) {
//3.判断共享数据(已经到末尾)
if (ticket == 0) {
break;
} else {
//4.判断共享数据(没有到末尾)
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
ticket--;
System.out.println(getName() + "在卖票,还剩下" + ticket + "张票!!!");
}
}
}
}
}
package lx1;
public class demo1 {
public static void main(String[] args) {
/*
一共有1000张电影票,可以在两个窗口领取,假设每次领取的时间为3000毫秒,
要求:请用多线程模拟卖票过程并打印剩余电影票的数量
*/
//1.创建多线程
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.setName("窗口1");
t2.setName("窗口2");
//2.启动线程
t1.start();
t2.start();
}
}
练习2
package lx2; /* 有100份礼品,两人同时发送,当剩下的礼品小于10份的时候则不再送出, 利用多线程模拟该过程并将线程的名字和礼物的剩余数量打印出来. */ public class MyThread extends Thread { static int liping = 100; @Override public void run() { //1.循环 while (true) { //2.同步代码块 synchronized (MyThread.class) { //3.判断共享数据(已经到了末尾) if (liping == 0) { break; } else { //4.判断共享数据(没有到末尾) //当剩下的礼品小于10份的时候则不再送出 try { Thread.sleep(00); } catch (InterruptedException e) { throw new RuntimeException(e); } if (liping < 10) { break; } liping--; System.out.println(getName() + "还剩余" + liping + "份礼品"); } } } } }
package lx2; public class demo1 { public static void main(String[] args) { /* 有100份礼品,两人同时发送,当剩下的礼品小于10份的时候则不再送出, 利用多线程模拟该过程并将线程的名字和礼物的剩余数量打印出来. */ //1,创建多线程对象 MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); t1.setName("小明"); t2.setName("小华"); //2.启动线程 t1.start(); t2.start(); } }
练习3
package lx3;
/*
同时开启两个线程,共同获取1-100之间的所有数字。
要求:将输出所有的奇数。
*/
public class MyRunable implements Runnable {
//采用第二种方式实现多线程 不需要加上static修饰 因为创建的线程对象是MyRunable的实例对象,而实例对象是唯一的
int number = 1;
@Override
public void run() {
//1.循环
while (true) {
//2.同步代码块
synchronized (MyRunable.class) {
//3.判断共享数据(已经到末尾)
if (number > 100) {
break;
} else {
//4.判断共享数据(还没有到末尾)
if (number % 2 == 1) {
System.out.println(Thread.currentThread().getName() + "打印数字" + number);
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
number++;
}
}
}
}
}
package lx3;
public class Test {
public static void main(String[] args) {
/*
同时开启两个线程,共同获取1-100之间的所有数字。
要求:将输出所有的奇数。
*/
//创建多线程对象,表示多线程要执行的任务
MyRunable mr = new MyRunable();
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
t1.setName("线程1");
t2.setName("线程2");
//启动线程
t1.start();
t2.start();
}
}
练习4
package lx4;
import java.util.Random;
/*
微信中的抢红包也用到了多线程。
假设:100块,分成了3个包,现在有5个人去抢。
其中,红包是共享数据。
5个人是5条线程。
打印结果如下:
XXX抢到了XXX元
XXX抢到了XXX元
XXX抢到了XXX元
XXX没抢到
XXX没抢到
*/
public class Mythread extends Thread {
//共享数据
//100块,分成了3个包
static double money = 100;
static int count = 3;
//设置最小的中奖金额
static final double MIN = 0.01;
@Override
public void run() {
//同步代码块
synchronized (Mythread.class) {
//判断共享数据是否到了末尾(已经到了末尾)
if (count == 0) {
System.out.println(getName() + "没有抢到红包!");
} else {
/*
不能随机随机
现在有100元
第一次随机从100里面随机一个金额 比如说50
第二次随机就要从剩下来的50元里面随机 比如说30
第三次随机就直接把剩下的的20元当做抽取到的红包即可 没必要随机了
*/
//判断共享数据是否到了末尾(还没有到了末尾)
//定义一个变量,表示抽到红包的金额
double price = 0;
if (count == 1) {
//表示最后一个红包
//就无需随机 ,剩下的所有的钱都是中奖金额
price = money;
} else {
//表示第一次或者第二次抽取红包(随机)
Random r = new Random();
//现在有100元 3个红包
//第一次最多抽取99.98 因为还剩下2个红包要抽取,最小金额是0.01元
//100-(3-1)*0.01=99.98
double bounds = money - (count - 1) * MIN;
price = r.nextDouble(bounds) + MIN;//不包括抽取金额为0 所以加上最小金额0.01 0.01-99.99 不包括99.99
}
//从money当中,去掉当前中奖的金额
money -= price;
//红包的个数-1
count--;
//本次红包的信息进行打印
System.out.println(getName() + "抢到了" + price + "元");
}
}
}
}
package lx4;
public class Test {
public static void main(String[] args) {
/*
微信中的抢红包也用到了多线程。
假设:100块,分成了3个包,现在有5个人去抢。
其中,红包是共享数据。
5个人是5条线程。
打印结果如下:
XXX抢到了XXX元
XXX抢到了XXX元
XXX抢到了XXX元
XXX没抢到
XXX没抢到
*/
//一次线程只能执行一次完整的run方法
Mythread t1 = new Mythread();
Mythread t2 = new Mythread();
Mythread t3 = new Mythread();
Mythread t4 = new Mythread();
Mythread t5 = new Mythread();
t1.setName("张三");
t2.setName("王五");
t3.setName("李四");
t4.setName("赵六");
t5.setName("小小");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
练习5
package lx5;
/*
有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700};
创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”,“抽奖箱2”
随机从抽奖池中获取奖项元素并打印在控制台上,格式如下:
每次抽出一个奖项就打印一个(随机)
抽奖箱1 又产生了一个 10 元大奖
抽奖箱1 又产生了一个 100 元大奖
抽奖箱1 又产生了一个 200 元大奖
抽奖箱1 又产生了一个 800 元大奖
抽奖箱2 又产生了一个 700 元大奖
.....
*/
import java.util.ArrayList;
import java.util.Collections;
public class MyThread extends Thread {
//共享数据
// 奖励的金额
ArrayList<Integer> list;
public MyThread(ArrayList<Integer> list) {
this.list = list;
}
/*
我们采用随机抽一个删一个的方法
*/
@Override
public void run() {
//1.循环
while (true) {
//同步代码块
synchronized (MyThread.class) {
//判断共享数据是否到了末尾(到了末尾)
if (list.size() == 0) {
break;
} else {
//判断共享数据是否到了末尾(还没有到末尾)
//随机一个删一个
Collections.shuffle(list);
int index = list.get(0);
System.out.println(getName() + "又产生了一个" + index + "元大奖");
list.remove(0);
}
}
/*
把sleep代码写在锁的外面
因为当线程1进去了,如果你sleep写在锁里面,导致线程1睡了,线程2就无法进入锁了。
写在外面,线程1执行完了,锁就开了,线程1睡100ms 线程2就有机会抢到cpu执行权
*/
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
package lx5;
import java.util.ArrayList;
import java.util.Collections;
public class Test {
public static void main(String[] args) {
/*
有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700};
创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”,“抽奖箱2”
随机从抽奖池中获取奖项元素并打印在控制台上,格式如下:
每次抽出一个奖项就打印一个(随机)
抽奖箱1 又产生了一个 10 元大奖
抽奖箱1 又产生了一个 100 元大奖
抽奖箱1 又产生了一个 200 元大奖
抽奖箱1 又产生了一个 800 元大奖
抽奖箱2 又产生了一个 700 元大奖
.....
*/
//创建抽奖箱奖池
ArrayList<Integer> list=new ArrayList<>();
Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
MyThread t1=new MyThread(list);
MyThread t2=new MyThread(list);
t1.setName("抽奖箱1");
t2.setName("抽奖箱2");
t1.start();
t2.start();
}
}
练习6
方法1
package lx6;
/*
有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700};
创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”,“抽奖箱2”
随机从抽奖池中获取奖项元素并打印在控制台上,格式如下:
每次抽的过程中,不打印,抽完时一次性打印(随机) 在此次抽奖过程中,抽奖箱1总共产生了6个奖项。
分别为:10,20,100,500,2,300最高奖项为300元,总计额为932元
在此次抽奖过程中,抽奖箱2总共产生了6个奖项。
分别为:5,50,200,800,80,700最高奖项为800元,总计额为1835元
*/
import java.util.ArrayList;
import java.util.Collections;
public class MyThread extends Thread {
//共享数据
// 奖励的金额
ArrayList<Integer> list;
public MyThread(ArrayList<Integer> list) {
this.list = list;
}
//线程1的
static ArrayList<Integer> list1 = new ArrayList<>();
//线程2的
static ArrayList<Integer> list2 = new ArrayList<>();
/*
我们采用随机抽一个删一个的方法
*/
@Override
public void run() {
//1.循环
while (true) {
//同步代码块
synchronized (MyThread.class) {
//判断共享数据是否到了末尾(到了末尾)
if (list.size() == 0) {
break;
} else {
//判断共享数据是否到了末尾(还没有到末尾)
//随机一个删一个
Collections.shuffle(list);
int index = list.get(0);
// System.out.println(getName() + "又产生了一个" + index + "元大奖");
list.remove(0);
if ("抽奖箱1".equals(getName())) {
list1.add(index);
} else {
list2.add(index);
}
}
}
/*
把sleep代码写在锁的外面
因为当线程1进去了,如果你sleep写在锁里面,导致线程1睡了,线程2就无法进入锁了。
写在外面,线程1执行完了,锁就开了,线程1睡100ms 线程2就有机会抢到cpu执行权
*/
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
int sum1 = 0;
int max1 = 0;
for (Integer i : list1) {
sum1 += i;
if (max1 < i) {
max1 = i;
}
}
int sum2 = 0;
int max2 = 0;
for (Integer i : list2) {
sum2 += i;
if (max2 < i) {
max2 = i;
}
}
if ("抽奖箱1".equals(getName())) {
System.out.println(getName() + list1 + "最高奖项为" + max1 + "元,总计额为" + sum1 + "元");
} else {
System.out.println(getName() + list2 + "最高奖项为" + max2 + "元,总计额为" + sum2 + "元");
}
}
}
package lx6;
import java.util.ArrayList;
import java.util.Collections;
public class Test {
public static void main(String[] args) {
/*
有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700};
创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”,“抽奖箱2”
随机从抽奖池中获取奖项元素并打印在控制台上,格式如下:
每次抽的过程中,不打印,抽完时一次性打印(随机) 在此次抽奖过程中,抽奖箱1总共产生了6个奖项。
分别为:10,20,100,500,2,300最高奖项为300元,总计额为932元
在此次抽奖过程中,抽奖箱2总共产生了6个奖项。
分别为:5,50,200,800,80,700最高奖项为800元,总计额为1835元
*/
//创建抽奖箱奖池
ArrayList<Integer> list=new ArrayList<>();
Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
MyThread t1=new MyThread(list);
MyThread t2=new MyThread(list);
t1.setName("抽奖箱1");
t2.setName("抽奖箱2");
t1.start();
t2.start();
}
}
每个线程都有自己独立的栈空间
run方法里的集合是独立的,互相独立的
方法2
把集合的创建放在run方法里面,每个线程都会执行run方法,创建出不同空间的集合
package lx7;
/*
有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700};
创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”,“抽奖箱2”
随机从抽奖池中获取奖项元素并打印在控制台上,格式如下:
每次抽的过程中,不打印,抽完时一次性打印(随机) 在此次抽奖过程中,抽奖箱1总共产生了6个奖项。
分别为:10,20,100,500,2,300最高奖项为300元,总计额为932元
在此次抽奖过程中,抽奖箱2总共产生了6个奖项。
分别为:5,50,200,800,80,700最高奖项为800元,总计额为1835元
*/
import java.util.ArrayList;
import java.util.Collections;
public class MyThread extends Thread {
//共享数据
// 奖励的金额
ArrayList<Integer> list;
public MyThread(ArrayList<Integer> list) {
this.list = list;
}
/*
我们采用随机抽一个删一个的方法
*/
@Override
public void run() {
//创建集合 存放抽奖的奖项 这些集合都是根据线程的创建而创建的 就是每个线程创建一个集合
ArrayList<Integer> boxList = new ArrayList<>();
//1.循环
while (true) {
//同步代码块
synchronized (MyThread.class) {
//判断共享数据是否到了末尾(到了末尾)
if (list.size() == 0) {
break;
} else {
//判断共享数据是否到了末尾(还没有到末尾)
//随机一个删一个
Collections.shuffle(list);
int index = list.get(0);
list.remove(0);
//每个线程对对应的集合添加元素(集合不同)
boxList.add(index);
}
}
/*
把sleep代码写在锁的外面
因为当线程1进去了,如果你sleep写在锁里面,导致线程1睡了,线程2就无法进入锁了。
写在外面,线程1执行完了,锁就开了,线程1睡100ms 线程2就有机会抢到cpu执行权
*/
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
int sum = 0;
int max = 0;
for (Integer i : boxList) {
sum += i;
if (max < i) {
max = i;
}
}
//这里看起来只是打印一个集合,本质上是根据线程的多少打印出不同的集合
System.out.println(getName() + boxList + "最高奖项为" + max + "元,总计额为" + sum + "元");
}
}
package lx7;
import java.util.ArrayList;
import java.util.Collections;
public class Test {
public static void main(String[] args) {
/*
有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700};
创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”,“抽奖箱2”
随机从抽奖池中获取奖项元素并打印在控制台上,格式如下:
每次抽的过程中,不打印,抽完时一次性打印(随机) 在此次抽奖过程中,抽奖箱1总共产生了6个奖项。
分别为:10,20,100,500,2,300最高奖项为300元,总计额为932元
在此次抽奖过程中,抽奖箱2总共产生了6个奖项。
分别为:5,50,200,800,80,700最高奖项为800元,总计额为1835元
*/
//创建抽奖箱奖池
ArrayList<Integer> list=new ArrayList<>();
Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
MyThread t1=new MyThread(list);
MyThread t2=new MyThread(list);
MyThread t3=new MyThread(list);
t1.setName("抽奖箱1");
t2.setName("抽奖箱2");
t3.setName("抽奖箱3");
t1.start();
t2.start();
t3.start();
}
}
这个方法强调的是每个线程创建出不同的集合,每个线程都有自己的集合
练习7
package lx8;
import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
/*
有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700};
创建两个抽奖箱(线程)设置线程名称分别为 "抽奖箱1", "抽奖箱2"
随机从抽奖池中获取奖项元素并打印在控制台上,格式如下:
在此次抽奖过程中,抽奖箱1总共产生了6个奖项,分别为:10,20,100,500,2,300
最高奖项为300元,总计额为932元
在此次抽奖过程中,抽奖箱2总共产生了6个奖项,分别为:5,50,200,800,80,700
最高奖项为800元,总计额为1835元
在此次抽奖过程中,抽奖箱2中产生了最大奖项,该奖项金额为800元
核心逻辑:获取线程抽奖的最大值(看成是线程运行的结果)
以上打印效果只是数据模拟,实际代码运行的效果会有差异
*/
//创建抽奖箱奖池
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list, 10, 5, 20, 50, 100, 200, 500, 800, 2, 80, 300, 700);
/*
1.定义一个类MyCallable实现Callable接口
2.在MyCallable类中重写call()方法 有返回值的表示多线程运行的结果
3.创建MyCallable类的对象 表示多线程要执行的任务
4.创建Future的实现类FutureTask对象,把MyCallable对象作为构造方法的参数 作用:管理多线程运行的结果
5.创建Thread类的对象,把FutureTask对象作为构造方法的参数 表示线程
6.启动线程
7.再调用get方法,就可以获取线程结束之后的结果。
*/
Mycallable m = new Mycallable(list);
FutureTask<Integer> ft = new FutureTask<>(m);
Thread t1 = new Thread(ft);
Thread t2 = new Thread(ft);
t1.setName("抽奖箱1");
t2.setName("抽奖箱2");
t1.start();
t2.start();
//获取多线程的运行结果
Integer result = ft.get();
System.out.println(result);
}
}
package lx8;
import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
/*
有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700};
创建两个抽奖箱(线程)设置线程名称分别为 "抽奖箱1", "抽奖箱2"
随机从抽奖池中获取奖项元素并打印在控制台上,格式如下:
在此次抽奖过程中,抽奖箱1总共产生了6个奖项,分别为:10,20,100,500,2,300
最高奖项为300元,总计额为932元
在此次抽奖过程中,抽奖箱2总共产生了6个奖项,分别为:5,50,200,800,80,700
最高奖项为800元,总计额为1835元
在此次抽奖过程中,抽奖箱2中产生了最大奖项,该奖项金额为800元
核心逻辑:获取线程抽奖的最大值(看成是线程运行的结果)
以上打印效果只是数据模拟,实际代码运行的效果会有差异
*/
//创建抽奖箱奖池
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list, 10, 5, 20, 50, 100, 200, 500, 800, 2, 80, 300, 700);
/*
1.定义一个类MyCallable实现Callable接口
2.在MyCallable类中重写call()方法 有返回值的表示多线程运行的结果
3.创建MyCallable类的对象 表示多线程要执行的任务
4.创建Future的实现类FutureTask对象,把MyCallable对象作为构造方法的参数 作用:管理多线程运行的结果
5.创建Thread类的对象,把FutureTask对象作为构造方法的参数 表示线程
6.启动线程
7.再调用get方法,就可以获取线程结束之后的结果。
*/
//创建多线程要运行的参数对象
Mycallable m = new Mycallable(list);
//创建多线程运行结果的管理者对象
FutureTask<Integer> ft1 = new FutureTask<>(m);
FutureTask<Integer> ft2 = new FutureTask<>(m);
//创建线程对象
Thread t1 = new Thread(ft1);
Thread t2 = new Thread(ft2);
t1.setName("抽奖箱1");
t2.setName("抽奖箱2");
t1.start();
t2.start();
//获取多线程的运行结果
Integer result1 = ft1.get();
System.out.println(result1);
Integer result2 = ft2.get();
System.out.println(result2);
// 在此次抽奖过程中,抽奖箱2中产生了最大奖项,该奖项金额为800元
if (result1 > result2) {
System.out.println("在此次抽奖过程中,抽奖箱1中产生了最大奖项,该奖项金额为800元");
} else {
System.out.println("在此次抽奖过程中,抽奖箱2中产生了最大奖项,该奖项金额为800元");
}
}
}