`

小谈java多线程

    博客分类:
  • java
阅读更多

关键字:Synchronized、wait/notify、ReentrantLock、生产-消费者模型

 

这篇博文仅仅对java多线程的部分知识做个小结,欢迎大家补充。

 

Synchronized

     说到多线程,大家(对于初学者来说)可能就会想到Synchronized这个关键字。Synchronized可以用在方法级别上,用来同步一个方法的访问,也可以同步一个代码块。形式如下:

 

// 同步方法
public synchronized  void method(){

   // 方法体

}

// 同步代码快
synchronized(object){

     // 代码块

}

Synchronized 需要注意的是:Synchronized作用于方法时,Synchronized首先会对方法所属的对象加锁,对象的其他被Synchronized修饰的方法都不可以被其他线程访问,非Synchronized修饰发方法可以被多个线程同时访问。

 

wait/notify

    wait/notify必须在Synchronized的作用范围内使用,也就是说wait/notify必须在同步方法体内或同步代码快内才有效,其他地方就会报IllegalMonitorStateException。

 

基于Synchronized、wait/notify机理实现生产-消费者模型

 

public class Basket {
	private List<String> basket = new ArrayList<String>(10);
	private boolean running = false ;
	
	public void run(){
		this.running = true;
	}
	
	public void stop(){
		this.running = false;
	}
	
	public boolean isRunning(){
		return running;
	}
	
	public void add(String e) {
		synchronized (basket) {
			while (basket.size() == 10) {
				try {
					basket.wait(); // 访问的线程会等待在此处,当再次被唤醒,从此处继续执行
				} catch (InterruptedException ex) {
					ex.printStackTrace();
				}
			}
			basket.add(e);
			String currentThreadName = Thread.currentThread().getName();
			System.out.println("线程["+currentThreadName+"]   "+e + " 生产一个产品");
			basket.notifyAll();
		}
	}

	public void remove(String msg) {
		synchronized (basket) {
			String currentThreadName = Thread.currentThread().getName();
			while (basket.size() == 0) {
				try {
					System.out.println("线程["+currentThreadName+"]   "+msg + ": please wait a little");
					basket.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			String result = basket.get(0);
			basket.remove(0);
			System.out.println("线程["+currentThreadName+"]   "+msg + " 消费:" + result);
			basket.notifyAll();
		}
	}
	

	public void getResult() {
		System.out.println(basket.toString());
	}
}

生产者

class UProducer implements Runnable {

	private String name = "";
	private Basket basket;

	public UProducer(String name, Basket basket) {
		this.name = name;
		this.basket = basket;
	}

	@Override
	public void run() {
		int i = 0;
		while(basket.isRunning()){
			basket.add(name + i++);
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public String getName() {
		return name;
	}
} 

消费者

class Customer implements Runnable {

	private String name = "";
	private Basket basket;

	public Customer(String name, Basket basket) {
		super();
		this.name = name;
		this.basket = basket;
	}

	@Override
	public void run() {
		int i = 0;
		while(basket.isRunning()){
			basket.remove(name + i++);
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public String getName() {
		return name;
	}

} 

测试代码

 

	public static void main(String[] args) {
		Basket basket = new Basket();
		basket.run();
		UProducer mrZhang = new UProducer("张三", basket);
		UProducer mrLi = new UProducer("李四", basket);

		Customer missWang = new Customer("王五", basket);
		Customer missZhao = new Customer("赵六", basket);

		new Thread(missWang, missWang.getName()).start();
		new Thread(missZhao, missZhao.getName()).start();

		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		new Thread(mrZhang, mrZhang.getName()).start();
		new Thread(mrLi, mrLi.getName()).start();

		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		basket.stop();
		basket.getResult();
	}

 Synchronized关键字可以很方便的实现简单的多线程问题,jvm默认的为我们提供了对象的加锁、释放锁功能。Synchronized关键字同时存在一些问题。如一个线程得不到对象的锁会永远的等待。

 

ReentrantLock

  ReentrantLock是对Synchronized的加强,提供了线程竞争锁的等待时间、多条件下的线程等待策略等等强大的功能。

具体的方法请参考API

 

以下是对生产-消费者模型的改写

 

class Basket {
	private static final int CAPACITY = 10;
	private List<Bread> container = new ArrayList<Bread>(CAPACITY);

	private ReentrantLock lock = new ReentrantLock();
	private Condition notFull = lock.newCondition();
	private Condition notEmpty = lock.newCondition();

	public void add(Bread bread) {
		try {
			lock.lockInterruptibly();
			while (container.size() == CAPACITY) {
				System.out.println("货源[" + Thread.currentThread().getName() + "]:no more ,i will call you if i need");
				notFull.await();
			}
			container.add(bread);
			System.out.println("货源[" + Thread.currentThread().getName() + "]:进货:" + bread);
			notEmpty.signalAll();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	public void remove() {
		try {
			lock.lockInterruptibly();
			while (container.size() == 0) {
				System.out.println("销售[" + Thread.currentThread().getName() + "]: please wait a little");
				notEmpty.await();
			}
			Bread bread = container.get(0);
			container.remove(0);
			System.out.println("销售[" + Thread.currentThread().getName() + "]:销售:" + bread);
			notFull.signalAll();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}
}
class Bread {

	private String name;

	public Bread(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return name;
	}
}
 

 

0
2
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics