多线程问题的一些模型

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

 

posted @ 2019-09-11 01:10  德鲁大叔817  阅读(255)  评论(0编辑  收藏  举报