小谈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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic String toString() {return name;}}?
?