关键字: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;
}
}
分享到:
相关推荐
浅谈JAVA中多线程的实现
浅谈Java多线程编程.pdf
内含 chapter02-chapter18 共 17 个实例性源码项目,内容循序渐进,由入门到精通。尤其适合于没有 Java 线程开发经验的朋友。自己动手敲出本资源解压缩后的 ...相信你理解了此源码之后,即可步入 Java 多线程开发。
浅谈Java的多线程机制.pdf
浅谈JAVA中多线程的实现.pdf
主要介绍了浅谈Java多线程处理中Future的妙用(附源码),还是比较不错的,需要的朋友可以参考下。
对JAVA初学者学习多线程很有帮助,很经典的一篇文章
下面小编就为大家带来一篇浅谈java多线程 join方法以及优先级方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
浅谈JAVA语言的多线程技术.pdf
主要介绍了java多线程wait,notify,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,下面小编和大家一起来学习一下吧
主要介绍了浅谈Java多线程编程中Boolean常量的同步问题,主要针对线程之间同步了不同的布尔对象的问题,需要的朋友可以参考下
主要介绍了java多线程编程的相关资料,文中讲解非常细致,帮助大家更好的理解和学习java多线程,感兴趣的朋友可以了解下
下面小编就为大家带来一篇浅谈Java多线程实现及同步互斥通讯。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
主要介绍了浅谈Java多线程的优点及代码示例,还是比较不错的,这里分享给大家,需要的朋友可以参考。
参加工作以来,我编写并维护了若干C++/Java多线程网络服务程序,这本书总结了我在开发维护这类服务程序方面的经验。工作中,我没有写过单线程的网络服务程序,没有写过C语言的网络服务程序,也没有写过运行在Windows...
下面小编就为大家带来一篇浅谈java中异步多线程超时导致的服务异常。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
主要介绍了Java线程Thread之interrupt中断解析,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
主要介绍了浅谈Java获得多线程的返回结果方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧