Java多线程的例子及synchronized关键字锁定对象的用法

该例子所应用场景:一个线程负责生产,多个线程(该例为3个)负责消费;生产者不断的往堆栈中加入数据,消费者不断的从堆栈中取数据。

代码如下:

package com.xs.mail.thread;

import java.util.ArrayList;
import java.util.List;

class Widget {
}

class WidgetMaker extends Thread {
	List<Widget> finishedWidgets = new ArrayList<Widget>();

	public void run() {
		try {
			while (true) {
				//每1秒钟生产一个Widget
				Thread.sleep(1000);// act busy
				Widget w1 = new Widget();
				// 也就是说需要5秒钟才能新产生一个Widget,这决定了一定要用notify而不是notifyAll
				// 因为上面两行代码不是同步的,如果用notifyAll则所有线程都企图冲出wait状态
				// 第一个线程得到了锁,并取走了Widget(这个过程的时间小于5秒,新的Widget还没有生成)
				// 并且解开了锁,然后第二个线程获得锁(因为用了notifyAll其他线程不再等待notify语句
				// ,而是等待finishedWidgets上的锁,一旦锁放开了,他们就会竞争运行),运行
				// finishedWidgets.remove(0),但是由于finishedWidgets现在还是空的,
				// 于是产生异常
				// ***********这就是为什么下面的那一句不能用notifyAll而是要用notify

				synchronized (finishedWidgets) {
					finishedWidgets.add(w1);
					finishedWidgets.notify(); // 这里只能是notify而不能是notifyAll
				}
			}
		} catch (InterruptedException e) {
		}
	}

	public Widget waitForWidget() {
		synchronized (finishedWidgets) {
			if (finishedWidgets.size() == 0) {
				try {
					System.out.println("暂停线程:" + Thread.currentThread().getName());
					finishedWidgets.wait();
				} catch (InterruptedException e) {
				}
			}
			return finishedWidgets.remove(0);
		}
	}
}

public class WidgetUser extends Thread {
	private WidgetMaker maker;

	public WidgetUser(String name, WidgetMaker maker) {
		super(name);
		this.maker = maker;
	}

	public void run() {
		while (true) {
			Widget w = maker.waitForWidget();
			System.out.println(getName() + " got a widget");
		}
	}

	public static void main(String[] args) {
		WidgetMaker maker = new WidgetMaker();
		maker.start();
		new WidgetUser("Tom", maker).start();
		new WidgetUser("Jack", maker).start();
		new WidgetUser("Marry", maker).start();
	}
}


上一篇:关于DWR的A request has been denied as a potential CSRF attack的错误


下一篇:改变nginx logrotate方式采用sh文件自动切割日志文件