JavaDay17-多线程(二)
五、锁
//Lock-测试类
public class LockDemo {
public static void main(String[] args) {
MyRun myRun = new MyRun();
Thread thread1 = new Thread(myRun);
Thread thread2 = new Thread(myRun);
Thread thread3 = new Thread(myRun);
thread1.start();
thread2.start();
thread3.start();
}
}
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MyRun implements Runnable{
private int ticket;
//创建锁对象,Lock是接口,需要创建其实现类ReentrantLock的对象
//static实现共享
static Lock lock = new ReentrantLock();
@Override
public void run() {
while (true){
//调用lock()方法
lock.lock();
try {
if(ticket<100){
System.out.println(ticket);
ticket++;
}else {
break;
}
} catch (Exception e) {
throw new RuntimeException(e);
//finally保证必须调用一次unlock()方法
}finally {
lock.unlock();
}
}
}
}
六、等待唤醒机制
1、生产者(线程)
循环--同步代码块--判断末尾--判断非末尾
2、消费者(线程)
循环--同步代码块--判断末尾--判断非末尾
3、第三方-管理共享资源
flag\count\lock
//等待唤醒机制-测试类
public class Test {
public static void main(String[] args) {
Foodie foodie = new Foodie();
Cook cook = new Cook();
foodie.setName("吃货");
cook.setName("厨师");
foodie.start();
cook.start();
}
}
//生产者
public class Cook extends Thread{
@Override
public void run() {
while (true){
synchronized (Desk.lock){
if (Desk.count==0){
break;
}else {
if (Desk.flag==0){
System.out.println("厨师做了一碗面!!");
Desk.lock.notifyAll();
Desk.flag=1;
}else {
try {
Desk.lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
}
}
//消费者
public class Foodie extends Thread{
@Override
public void run() {
/*
循环--同步代码块--判断末尾--判断非末尾
*/
while (true){
synchronized (Desk.lock){
if(Desk.count==0){
break;
}else {
if (Desk.flag==1){
Desk.count--;
System.out.println("还能再吃"+Desk.count+"碗!!");
Desk.lock.notifyAll();
Desk.flag=0;
}else {
try {
Desk.lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
}
}
//管理共享资源
public class Desk {
//flag
public static int flag;
//count
public static int count=10;//共享资源
//lock
public static Object lock=new Object();
}
七、阻塞队列
1、实现了4种接口:iterable\Collection\Queue\BlockingQueue
2、实现类:
- ArrayBlockingQueue:底层是数组,有界
- LinkedBlockingQueue:底层是链表,无界,但不是真正的无界,最大值为int的最大值。
//阻塞队列
public class QueueDemo {
public static void main(String[] args) {
//创建队列对象,需要指定数组的大小
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(1);
//创建线程对象,传递阻塞队列
Cook cook = new Cook(queue);
Foodie foodie = new Foodie(queue);
//开启线程
cook.start();
foodie.start();
}
}
//生产者
import java.util.concurrent.ArrayBlockingQueue;
public class Cook extends Thread{
//定义阻塞队列变量
ArrayBlockingQueue<String> queue;
//定义构造方法 传递阻塞队列对象
public Cook(ArrayBlockingQueue<String> queue) {
this.queue = queue;
}
@Override
public void run() {
while (true){
try {
//生产者调用队列的put()方法
queue.put("面条");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("厨师做了一碗面条");
}
}
}
//消费者
import java.util.concurrent.ArrayBlockingQueue;
public class Foodie extends Thread {
//定义阻塞队列的变量
ArrayBlockingQueue<String> queue;
//定义构造方法 传递阻塞队列对象
public Foodie(ArrayBlockingQueue<String> queue) {
this.queue = queue;
}
@Override
public void run() {
while (true){
try {
//消费者调用队列的take()方法
String take = queue.take();
System.out.println(take);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
八、线程的六种状态
1、新建状态(NEW)——创建线程对象
2、就绪状态(RUNNABLE)——start方法
3、阻塞状态(BLOCKED)——无法获得锁对象
4、等待状态(WAITING)——wait方法
5、计时等待(TIMED_WAITING)——sleep方法
6、结束状态(TERMINATED)——全部代码运行完毕
九、多线程练习
1、题目:卖电影票。
- 一共有1000张电影票,可以在每个窗口领取,假设每次领取的时间为3000毫秒
- 要求:用多线程模拟卖票过程并打印剩余电影票的数量
public class Question {
public static void main(String[] args) {
Sold sold = new Sold();
Thread thread1 = new Thread(sold);
Thread thread2 = new Thread(sold);
thread2.start();
thread1.start();
}
}
public class Sold implements Runnable{
private static int count;//共享资源
static Object obj=new Object();//锁对象
@Override
public void run() {
while (true){//循环
synchronized (obj){//同步代码块
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (count>=1000){//先写末尾
break;
}else {//后写主要逻辑
count++;
System.out.println(Thread.currentThread().getName()+"还剩"+(1000-count)+"张票");
}
}
}
}
}
2、题目:有100份礼物,两人同时发送,当剩下的礼品小于10份则不再送出
- 要求:利用多线程模拟该过程并将线程的名字和礼物的剩余数量打印出来
public class Question {
public static void main(String[] args) {
Give give=new Give();
Thread t1=new Thread(give);
Thread t2=new Thread(give);
t1.start();
t2.start();
}
}
public class Give implements Runnable{
private static int count=100;
@Override
public void run() {
while (true){
synchronized (Give.class){
if(count>100){
break;
}else {
if (count<10){
break;
}else {
System.out.println(Thread.currentThread().getName()+"还剩"+count+"份礼物");
count--;
}
}
}
}
}
}
3、题目:同时开启两个线程,共同获取1-100之间的所有数字
- 要求:输出所有的奇数
public class Question {
public static void main(String[] args) {
Print print = new Print();
Thread thread1 = new Thread(print);
Thread thread2 = new Thread(print);
thread1.start();
thread2.start();
}
}
public class Print implements Runnable{
private static int count;
@Override
public void run() {
while (true){
synchronized (Print.class){
if (count>=100){
break;
}else {
count++;
if (count%2==1){
System.out.println(Thread.currentThread().getName()+" "+count);
}
}
}
}
}
}
4、问题:抢红包
- 总金额100,分为3个包,5个人抢
- 红包是共享数据
- 5个人是5条线程
public class Question {
public static void main(String[] args) {
Grab grab = new Grab();
Thread thread1 = new Thread(grab);
Thread thread2 = new Thread(grab);
Thread thread3 = new Thread(grab);
Thread thread4 = new Thread(grab);
Thread thread5 = new Thread(grab);
thread1.setName("1");
thread2.setName("2");
thread3.setName("3");
thread4.setName("4");
thread5.setName("5");
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread5.start();
}
}
import java.util.Random;
public class Grab implements Runnable{
//红包总金额
private static double money=100;
//抢红包的次数
private static int count;
//红包的最小金额
private static final double MIN=0.01;
@Override
public void run() {
while (true){
synchronized (Grab.class){
//只有3个红包
if (count>=3){
System.out.println(Thread.currentThread().getName()+"没有抢到红包");
}else {
double price=0;
//最后一次抢
if (count==2){
price=money;
}else {
Random random = new Random();
double bounds=money-(2-count)*MIN;
price = random.nextDouble(bounds);
if (price<MIN){
price=MIN;
}
}
//更新money
money=money-price;
count++;
System.out.println(Thread.currentThread().getName()+"抢到红包"+price);
}
}
break;
}
}
}

浙公网安备 33010602011771号