synchronize和生产者消费者模式

本文介绍了Java中的线程同步机制,包括synchronized关键字、wait()、notify()和notifyAll()方法,并通过生产者消费者模式的实际应用,展示了这些同步机制如何在多线程环境中确保数据的一致性和线程的安全交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. synchronize关键字

    synchronize可以用来对方法或者代码块加锁,使得被加锁的代码在同一时间只能被单个线程访问。

    Java中,每个对象都有一个对象锁,简单的说就是每个对象都可以作为一把锁来使用,将synchronized关键字作用于一个对象,就是将该对象作为锁来锁住一段代码。将synchronized作用于一个方法其实就是使用当前类的实例作为锁对象来锁住方法体中的代码。

2. wait()

    锁对象的wait方法用来休眠一个线程并释放当前获取到的锁,同时将该线程加入该锁对象的等待列表。从方法名也可以看出,该方法执行的效果是“等待”,也就是等待某个条件满足后再唤醒当前线程继续执行。

3. notify()和notifyAll()

    锁对象的notify方法用来唤醒一个该对象等待列表中的线程。notifyAll用来唤醒等待列表中的所有线程。

 

4. 生产者消费者模式

    生产者消费者模式是经典的线程同步模式,生产者生产一定量的产品放在缓冲区中,消费者从缓冲区中取走产品消费。该模式的关键在于生产者只有在缓冲区未满时才能放入产品,否则需要等待;而消费者只有在缓冲区有数据时才能拿到产品并消费,否则也需要等待。

    用代码实现该模式,我们设计4个类,Producer、Consumer、Table、Food,Producer负责生产Food,生产出的Food放在Table上,Consumer从Table上拿走Food。

Food类:

public class Food
{
    /**
     * food编号
     */
    private String no;
    
    public Food(String no)
    {
        this.no = no;
    }

    public String getNo()
    {
        return no;
    }

    public void setNo(String no)
    {
        this.no = no;
    }
    
    public String toString()
    {
        return "Food-"+no;
    }
}


Producer类:

public class Producer implements Runnable
{
    /**
     * 产品编号
     */
    private int mPrductNo = 0;
    
    /**
     * 产品存储缓冲区
     */
    private Table mTable;
    
    public Producer(Table table)
    {
        this.mTable = table;
    }
    
    private void produce(Table table)
    {
        synchronized (table)
        {
            mPrductNo++;
            Food food = new Food(String.valueOf(mPrductNo));
            
            if (mTable.size() >= Table.MAX_SIZE)
            {
                try
                {
                    table.wait();
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
            table.putFood(food);
            table.notifyAll();
        }
    }
    
    @Override
    public void run()
    {
        //生产100个产品
        for (int i=0; i<100; i++)
        {
            produce(mTable);
        }
    }
}

Consumer类:

public class Consumer implements Runnable
{
    private Table mTable;
    
    public Consumer(Table table)
    {
        this.mTable = table;
    }
    
    private void consume(Table table)
    {
        synchronized (table)
        {
            if (table.size() <= 0)
            {
                try
                {
                    table.wait();
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                    return;
                }
            }
            Food food = table.getFood();
            table.notifyAll();
        }
    }
    
    public void run()
    {
        for (int i=0; i <100; i++)
        {
            consume(mTable);
        }
    }
}

Table类:

public class Table
{
    public static final int MAX_SIZE = 10;
    
    private Queue<Food> tableQueue = new LinkedList<Food>();
    
    public Object lock = new Object();
    
    public void putFood(Food food)
    {
        tableQueue.offer(food);
    }
    
    public Food getFood()
    {
        return tableQueue.poll();
    }
    
    public void show()
    {
        StringBuffer foodInTable = new StringBuffer("");
        for (Food food : tableQueue)
        {
            foodInTable.append(food);
            foodInTable.append(",");
        }
    }
    
    public int size()
    {
        return tableQueue.size();
    }
}


    Producer的produce方法 用来生产一个产品,由于Table也会被Consumer线程访问到并且修改其数据,所以在对Table进行put、get操作时需要加锁,我们使用Producer、Consumer共享的Table实例作为锁对象。在生产出Food后,我们需要判断table是否已被放满产品,如果已被放满,那么Producer线程就需要等待,等table中有空余空间时再放入产品,我们使用wait方法让Producer休眠并释放获取的锁。如果table中有空余空间,那么Producer会调用table的put方法放入一个产品,由于放入产品前table可能为空,那么会有Consumer在等待获取产品,所以放入产品后,Producer会调用table.notifyAll()去唤醒正在等待的Consumer对象。Consumer对象被唤醒后会调用table.getFood()方法获取产品。Consumer获取产品的代码和Producer类似。

    




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值