您当前的位置: 首页 > 

梁云亮

暂无认证

  • 1浏览

    0关注

    1211博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

多线程 之 线程同步

梁云亮 发布时间:2020-02-10 23:26:06 ,浏览量:1

示例:多窗口售票。
  • 第一步:定义类表示车票池类:
public class TicketPool {
    private int ticketAmount =20; //值表示一共有多少张票,票号

    public synchronized  int getTicket(){ //锁的是当前对象,即票池
        int temp = ticketAmount;
        if(ticketAmount == 0){
            return 0;  //没有票了
        }
        ticketAmount -- ; //每卖出一张总票数减1
        return temp; //返回当前售出的票号
    }
}
  • 第二步:定义售票员类:
public class Saler extends Thread {
    private String name;
    private  TicketPool pool;

    public Saler(String name,TicketPool pool) {
        super();
        this.name = name;
        this.pool = pool;
    }

    @Override
    public void run() {//卖票
        while (true){
            int ticketNum = pool.getTicket();//从票池中取票
            if(ticketNum ==0){
                return;
            }
            System.out.println(name+":"+ticketNum);
        }
    }
}
  • 测试代码:
public class TicketTest {
    public static void main(String[] args) {
        TicketPool pool = new TicketPool();
        Saler zhangsan = new Saler("张三",pool);
        Saler tom = new Saler("tom",pool);
        zhangsan.start();
        tom.start();
    }
}
生产消费 演示由于生产的快消费的慢导致爆仓的情况
  • 产品池
public class ProductPool {
    private LinkedList pool = new LinkedList();//存放产品

    //同一时刻只能有一个生产者
    public synchronized int add(Integer item) { //返回当前生产的产品
        pool.add(item); //增加产品
        return item;
    }
	//同一时刻只能有一个消费者
    public synchronized int remove() { //返回当前消费的产品
        if (pool.isEmpty()) { //如果产品池为空的话,返回-1
            return -1;
        }
        return pool.removeFirst();
    }
}
  • 生产者
public class Producer extends Thread {
    private static int index = 0; //产品标识

    private String name;
    private ProductPool pool;

    public Producer(String name, ProductPool pool) {
        this.name = name;
        this.pool = pool;
    }

    @Override
    public void run() {
        while (true) { //一直不停地生产
            int res = pool.add(index++); //将产品放到产品池中
            System.out.println(name+"+"+res);
        }
    }
}
  • 消费者
public class Consumer extends Thread {
    private String name;
    private ProductPool pool;

    public Consumer(String name, ProductPool pool) {
        this.name = name;
        this.pool = pool;
    }

    @Override
    public void run() { //一直不停地消费
        while (true) {
            int res = pool.remove(); //从产品池中移除产品
            System.out.println(name+"-"+res);
        }
    }
}
  • 测试代码
public static void main(String[] args) {
    ProductPool pool = new ProductPool();
    Producer p1 = new Producer("p1", pool);
    Producer p2 = new Producer("p2", pool);
    Consumer c1 = new Consumer("c", pool);
    p1.start();
    p2.start();
    c1.start();
}
  • 运行程序 为了尽快看到程序出错效果(内存溢出),配置运行选项: 在这里插入图片描述 结果: 在这里插入图片描述 解决办法:指定一个变量,标记产品池中最多能放多少产品。当产品达到这个阀值时,不再生产,当低于这个值时再生产。
采用等待+通知的方式解决爆仓问题
  • 产品池
public class ProductPool {
    private int threshold = 100; //创建中产品数量最大值
    private LinkedList pool = new LinkedList();//放产品

    //同一时刻只能有一个人生产
    //返回增加后线程池中产品的数量
    public synchronized int add(Integer item) {
        //如果大于threshold,进入等待队列,释放锁控制权,别的线程拿到控制权后做自己具体的业务
        //有可能出现,当前线程在重新获取锁的控制权,开始往产品池中添加产品时,发现池子满的情况,所以此处不采用if而使用while
        //如果再次获取锁控制权,就继续执行上次wait后面的代码,wait之后首先再次执行while循环,再次判断,如果还是满的,就再等……直到仓库不满时才能添加
        // 当线程被唤醒后,它就立即获取锁控制权,从之前等待的位置继续运行
        // 拓展:wait一般和while循环结合使用
        while (pool.size() >= threshold) {
            try {
                this.wait(); //将当前线程放到等待队列中(谁在调用这个方法,谁就是当前线程)
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        pool.add(item); //增加产品,当获取到通知被唤醒时,线程获取锁的控制权,执行这行代码
        // System.out.println("++++"+pool.size()); //生产之后产品的数量
        notify();//增加完商品之后,通知别的线程可以生产or消费了
        return item;
    }

    // 同一时刻只能有一个人消费
    public synchronized int remove() {//返回当前取到的产品
        while (pool.isEmpty()) {
            try {
                this.wait();//如果仓库中没有产品,线程就等着
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Integer res = pool.removeFirst();
       // System.out.println("----"+pool.size()); //消费之后,仓库中产品的数量 
        notify();//消费完商品之后,通知别的线程可以生产or消费了
        return res;
    }
}
  • 生产者
public class Producer extends Thread {

    private static int index = 0;

    private String name;
    private ProductPool pool;

    public Producer(String name, ProductPool pool) {
        this.name = name;
        this.pool = pool;
    }

    @Override
    public void run() {
        while (true) {//在产品池中不断的生产
            int res = pool.add(index++);
            System.out.println(name+"+ "+res);
        }

    }
}
  • 消费者
public class Consumer extends Thread {
    private String name;
    private ProductPool pool;

    public Consumer(String name, ProductPool pool) {
        this.name = name;
        this.pool = pool;
    }

    @Override
    public void run() {
        while (true) {//在产品池中不断的消费
            int res = pool.remove();
            System.out.println(name+"-"+res);
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 测试代码
public class DemoTest {
    public static void main(String[] args) {
        ProductPool pool = new ProductPool();
        Producer p1 = new Producer("p1", pool);
        Producer p2 = new Producer("p2", pool);
        Consumer c1 = new Consumer("c1", pool);
        Consumer c2 = new Consumer("c2", pool);
        Consumer c3 = new Consumer("c3", pool);
        p1.start();
        p2.start();
        c1.start();
        c2.start();
        c3.start();
    }
}
采用等待+通知的方式解决爆仓问题:代码改进
  • 产品池
public class ProductPool {
    private int threshold = 100;
    private LinkedList pool = new LinkedList();//存放产品

    //同一时刻只能有一个人生产
    public void add(Integer item) {
        synchronized (this) {
            String name = Thread.currentThread().getName();
            while (pool.size() >= threshold) {
                try {
                    System.out.println(name + ".wait()");
                    this.wait(); //将当前线程放到等待队列中(谁在调用这个方法,谁就是当前线程)
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            pool.add(item); //增加产品,当获取到通知被唤醒时,线程获取锁的控制权,执行这行代码
            System.out.println(name + "生产后总数量:" + pool.size());
            System.out.println(name + "发送了通知");
            notify();//增加完商品之后,通知别的线程可以生产or消费了
        }
    }

    // 同一时刻只能有一个人消费
    public void remove() {
        synchronized (this) {
            String name = Thread.currentThread().getName();
            while (pool.isEmpty()) {
                try {
                    System.out.println(name + ".wait()");
                    this.wait();//如果仓库中没有产品,线程就等着
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            pool.removeFirst();
            System.out.println(name + "消费后总数量:" + pool.size());
            System.out.println(name + "发送了通知");
            notify();//消费完商品之后,通知别的线程可以生产or消费了
        }
    }
}
  • 生产者
public class Producer extends Thread {

    private static int index = 0;

    private ProductPool pool;

    public Producer(ProductPool pool) {
        this.pool = pool;
    }

    @Override
    public void run() {
        while (true) {//在产品池中不断的生产
            pool.add(index++);
        }

    }
}
  • 消费者
public class Consumer extends Thread {
    private ProductPool pool;

    public Consumer(ProductPool pool) {
        this.pool = pool;
    }

    @Override
    public void run() {
        while (true) {//在产品池中不断的消费
            pool.remove();
            try {
                Thread.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 测试代码
public class DemoTest {
    public static void main(String[] args) {
        ProductPool pool = new ProductPool();
        Producer p1 = new Producer(pool);
        p1.setName("p1");
        Producer p2 = new Producer(pool);
        p2.setName("p2");
        Consumer c1 = new Consumer(pool);
        c1.setName("c1");

        p1.start();
        p2.start();
        c1.start();
    }
}
关注
打赏
1665409997
查看更多评论
立即登录/注册

微信扫码登录

0.0411s