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
原文:https://www.cnblogs.com/xbfchder/p/11504073.html