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();
}
}