• 多线程问题的一些模型


    1.一个多线程实例:

    描述:某个火车售票系统,有多个窗口,但是票只在同一个系统中存有:

    设计思路: 只存在一个系统:

                           设计细节: 使用单例设计模式确保多窗口公用一个对象,

                           使用Vector集合框架保证线程的并发的安全性;

                      多个窗口卖票,使用多线程模拟多个窗口,在run方法中采用组合的方式调用System 类的sellTicket()方法。

    代码如下:

    //Ticket 实体类
    
    public class Ticket {
        //起始站,终点,价格
        // 只有一些属性,一个对象包含很多属性,增强可读性
        //JavaBean , POJO
        String start;
        String end;
        Float price;  //大写,包装类
    
        public Ticket(String start, String end, Float price) {
            this.start = start;
            this.end = end;
            this.price = price;
        }
    
        public Ticket() {
        }
    
        public String getStart() {
            return start;
        }
    
        public String getEnd() {
            return end;
        }
    
        public Float getPrice() {
            return price;
        }
    
        public void setStart(String start) {
            this.start = start;
        }
    
        public void setEnd(String end) {
            this.end = end;
        }
    
        public void setPrice(Float price) {
            this.price = price;
        }
    
        //重写toString 方法,为了打印对象方便
        public String toString(){
            StringBuilder sb=new StringBuilder();
            sb.append(this.start).append("->").append(this.end).append("   价格").append(this.price);
            return new String(sb);
        }
    }
    
    
    
    //SystemTest类
    
    public class SystemTest {
    
        //只有一个系统: 设计单例模式
        private SystemTest(){
    
        }
    
        private static SystemTest st=new SystemTest();
        //静态: 保证唯一性
    
        public static  SystemTest getInstance(){
            //静态方法:通过类名可以调用
            return st;
        }
    
        //属性 ,集合 ArrayList,Vector -->synchronized,Stack
         private Vector<Ticket> tickets=new Vector<>();
    
        //当前系统创建后给,tickets集合赋值,用块完成
        {
            for (int i = 10; i < 100; i++) {
                tickets.add(new Ticket("北京"+i,"深圳"+i,i%5+5+25F));
            }
        }
    
        //设计一个方法,从集合内拿票
        public Ticket getTicket(){
    
            try {
              return  tickets.remove(0);
            } catch (Exception e) {
               return null;
                   //没有票的情况
            }
    
        }
    }
    
    
    //窗口 Windows类
    
    public class Window extends Thread{
        String windowName;
    
        public Window(String windowName){
            this.windowName=windowName;
        }
    
        @Override
        public void run() {
            //卖票
            sellTicket();
        }
        public void sellTicket(){
            while(true){
                SystemTest st=SystemTest.getInstance();
                //获得单例对象
    
                Ticket t=st.getTicket();
                //从Vector集合中获取票
    
                if(t==null){
                    System.out.println(windowName+"窗口票已卖完");
                    break;
                }
                System.out.println(windowName+"售出: "+t);
            }
        }
    }
    
    
    //TestMain  测试主类
    
    public class TestMain {
        public static void main(String[] args) {
            //有很多个窗口,每个窗口共有一个系统
            Window w1=new Window("北京站");
            Window w2=new Window("西安站");
            Window w3=new Window("重庆站");
    
            w1.start();
            w2.start();
            w3.start();
    
    
        }
    }

    2.轮流打印ABCABCABC.......10次:


    采用synchronized给对象上锁的方式,使得每次访问对象方法的线程不能同时进行,得一个一个来。

    具体:synchronized(Object){   }

    //Test类 即就是 要执行打印的类
    
    //轮流上锁
    
    //线程类跑起来就是一条线程
    public class Test implements Runnable{
    
        private String name;   // eg: "A"
        private Object pre;    //oa,ob,oc三个对象之间前后循环
        private Object self;   //自己
    
        public Test(String name, Object pre, Object self) {
            this.name = name;
            this.pre = pre;
            this.self = self;
        }
    
    
        //每个线程有每个线程的run方法。
        @Override
        public void run() {
            int count = 10;  //倒计时 打印10次
            while (count > 0) {
                synchronized (pre) {
                    synchronized (self) {
                        System.out.print(name);   //锁的代码块
                        count--;
    
                        self.notify();
                    }
                    try {
                        pre.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
            }
        }
    
    
    
    //    @Override
    //    public void run() {
    //        synchronized (pre){
    //            synchronized (self){  //此处锁的是while的循环体
    //                //先写自身逻辑在考虑上锁问题
    //                int count =10;
    //                while(count>0){
    //                    System.out.println(name+count);
    //                    count--;
    //                    self.notify();
    //                }
    //            }
    //            try {
    //                pre.wait();
    //            } catch (InterruptedException e) {
    //                e.printStackTrace();
    //            }
    //        }
    //    }
    }
    
    
    //测试主类:
    
    
    public class Main {
    
    
        public static void main(String[] args) throws InterruptedException {
            Object oa=new Object();
            Object ob=new Object();
            Object oc=new Object();
    
            new Thread(new Test("A",oc,oa)).start();
            Thread.sleep(1000);
    
            new Thread(new Test("B",oa,ob)).start();
            Thread.sleep(1000);
    
            new Thread(new Test("C",ob,oc)).start();
            Thread.sleep(1000);
        }
    
    }

    3.模拟哲学家进食的问题:

     题目描述:有四个哲学家,四支筷子,当他们同时拿起自己左右手边的筷子时,才能开始进食。

    //筷子实体类:
    
    public class Chopsticks {
        private int num;//
        public Chopsticks (int num){
            this.num=num;
        }
    
        public int getNum() {
            return num;
        }
    }
    
    
    //哲学家类
    
    //哲学家进餐问题,体现线程死锁
    public class Thinker extends Thread {
        String name;
        Chopsticks left;
        Chopsticks right;
        public Thinker(String name,Chopsticks left,Chopsticks right){
            this.name=name;
            this.left=left;
            this.right=right;
        }
        @Override
        public void run() {
            synchronized (left){   //当前访问left对象的线程,单独享有left对象的访问权
                System.out.println(this.name+"拿起了左手"+left.getNum()+"号筷子!");
                synchronized (right){
                    System.out.println(this.name+"拿起了右手"+right.getNum()+"号筷子!");
                    System.out.println(this.name+"开始吃饭饭啦~~~");
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    }
    
    
    //主测试类
    
    //a:1,2号
    //b:2,3号
    //c:3,4号
    //d:4,1号
    //a,b,c,d 四个哲学家竞争四个筷子
    public class TestMain {
        public static void main(String[] args) {
            //4个筷子
            Chopsticks c1=new Chopsticks(1);
            Chopsticks c2=new Chopsticks(2);
            Chopsticks c3=new Chopsticks(3);
            Chopsticks c4=new Chopsticks(4);
    
            //4个哲学家
            Thinker a=new Thinker("a",c2,c1);
            Thinker b=new Thinker("b",c3,c2);
            Thinker c=new Thinker("c",c4,c3);
            Thinker d=new Thinker("d",c1,c4);
    
            a.start();
            b.start();
            c.start();
            d.start();
    
        }
    }

    4.生产者消费者问题:

    问题描述: 有一个共同的仓库,生产者每次想仓库中放进一个元素,消费者每次从仓库中拿出一个货物。 但是放元素时仓库的容量是有限的,取货物时仓库为空不能取。

    代码如下:

    //仓库类:
    
    public class House {
    //    //生产者消费者使用同一个仓库-->单例模式 
    //    private House(){
    //                                       可以采用单例的方式使得生产者消费者公用同一个仓库,也可以使用传入参数的方式使得生产者消费者使用同一个参数。
    //    }
    //    private static House h=new House();
    //    public House getH(){
    //        return h;
    //    }
    
    
        //集合,仓库 放东西
        ArrayList<String> list=new ArrayList<>();
    
        //向集合内放东西,生产者
        //synchronized锁的是调用该方法的对象   ,即是仓库对象house
        //Synchronized锁的是调用该方法的对象 即就是每次只能一个线程进行访问该对象的synchronized方法,
       //当该方法是普通方法并且类中有多个synchronized修饰的方法时。每个对象只能有一个线程进入,并访问方法。
                      //生产者线程 或者是消费者线程
        public synchronized void add(){
            if(list.size()<20){
                list.add("a");
            }else{
    //            return;  //让方法执行到这里就结束方法
                try {
                    this.notifyAll();  //唤醒线程
                    this.wait();  //让当前线程等待,不是仓库等待  wait会释放锁
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
        }
    
        //从集合内拿东西,消费者
        public synchronized void  get(){
            if(list.size()>0){
                list.remove(0);
            }else{
    //            return;
                try {
                    this.notifyAll();
                    this.wait();//访问仓库的线程等待
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    
    
    //生产者类
    
    public class Producer extends Thread {
        //为了保证生产者消费者使用同一个仓库对象,添加一个属性
        //可以自己传入参数来控制对象的一致性,两个线程构造函数中使用同一个House对象  仓库对象
        private House house;
        public Producer(House house){
            this.house=house;
        }
    
        @Override
        public void run() {
            //方法重写,原则:名字,参数列表必须一致
            //一直向仓库内放元素
            while(true){
                house.add();     //使用house的add方法。  add方法时synchronized修饰的
                System.out.println("生产者存入了一件货物");
    
            }
        }
    }
    
    //消费者类:
    
    public class Consumer extends Thread {
        private House house;
        public Consumer(House house){
            this.house=house;
        }
    
        @Override
        public void run() {
            //一直从仓库拿东西
            while(true){
                house.get();
                System.out.println("消费者拿走了一件东西");
            }
        }
    }
    
    
    //测试主类
    
    public class TestMain {
        public static void main(String[] args) {
            House house=new House();
            Producer producer=new Producer(house);
            //设置线程优先级
            producer.setPriority(10);
            Consumer consumer=new Consumer(house);
            Consumer consumer2=new Consumer(house);
            producer.start();
            consumer.start();
            consumer2.start();
        }
    }

    lk

  • 相关阅读:
    OpenCV-C++ 图像上采样和降采样
    OpenCV-C++ 图像形态学操作应用-提取水平与垂直线
    OpenCV-C++ 图像形态学操作
    OpenCV-C++ 图像滤波(二)-中值滤波-双边滤波
    OpenCV-C++ 图像滤波(一)-均值滤波-高斯滤波
    OpenCV-C++ 绘制基本形状与编写文字
    OpenCV-C++ 调整图像亮度和对比度
    OpenCV-C++ 图像混合
    Mysql新建表,插入中文时报错“Incorrect string value: 'xE4xBDxA0xE5xA5xBD' for column”问题
    springcloud11 spring cloud config
  • 原文地址:https://www.cnblogs.com/xbfchder/p/11504073.html
Copyright © 2020-2023  润新知