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;
        }
    }
}
posted @ 2023-04-14 23:51  小园初来乍到  阅读(24)  评论(0)    收藏  举报