线程通信我认为是多线程中最难掌握的部分了,这里通过两个例子来说明一下。
第一个:
使用两个线程打印 1-100. 线程1, 线程2 交替打印
public class Print implements Runnable{
int i = 1;
public void run(){
while(true){
synchronized(this){
if(i<100){
notify();
System.out.println(Thread.currentThread().getName() + ":" + i);
i++;
try{
wait();
} catch(Exception e){
System.out.println(e.getMessage());
}
} else {
break;
}
}
}
}
}
public static void main(String[] args){
Print p = new Print();
Thread t1 = new Thread(p);
Thread t2 = new Thread(p);
t1.start();
t2.start();
}
第二个例子:
生产者消费者:
生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品,店员一次只能持有固定数量的产品(比如:20),
如果生产者试图生产更多的产品,店员会叫生产者停一下,如果店中有空位放产品了再通知生产者继续生产;
如果店中没有产品了,店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。
问题分析:
1.是否涉及到多线程?是,生产者和消费者
2.是否涉及到多线程同步?是,生产者消费者操作共享数据
3.是否有线程通信?是。
public class Productor implements Runnable{
Clerk clerk = null; //要保证这个对象是共享数据,在它创建对象的时候,给它传同一个clerk对象
public Productor(Clerk clerk){
this.clerk = clerk;
}
public void run(){
//无限制的生产产品
//大家想想,直接在这里写生产合适吗?
//直接在这里写,无法操作共享数据了。所以我们直接让clerk增加产品就好。
while(true){
//如果出现问题,我们把这个问题放大。
try{
Thread.currentThread.sleep(10);
}catch(Exception e){
......
}//还记得昨天我说的吗?这个sleep写在这里必须处理
clerk.addProduct();
}
}
}
同样的消费者我就不详细写了,和上面的一样。
public class Consumer implements Runnable{
......
public void run(){
....
clerk.getProduct();
}
}
来写Clerk类:
public class Clerk{
int product;//这就是我们要操作的共享数据
public synchronized void addProduct(){
if(product >= 20){
try{
wait();//生产超过20个了,我们等消费者拿走再生产
}catch (){
....
}
}else{
System.out.println(Thread......getName() + "生产了一个产品,现在共" + product + "个");
product++;
notify();//或许这个时候,因为没有产品,消费者正在等待,我们生产了产品,就把它唤醒,可以拿走了。
}
}
//与上面类似。。。。
public synchronized void getProduct(){
if(product <= 0){
wait();
......
}else{
......
}
}
}
测试类我就不写了,可以自己试试。
至此,关于多线程的回顾就结束了,我们需要学习的是,处理多线程的思路,我上面已经说过。
问题不明显的时候,我们通过sleep()方法可以将问题放大。
但是我们在处理这类问题的时候,我们可以将这些不相关的东西删掉。关注问题本质,比如是否发生了共享数据的交叉,死锁等问题。
还有就是,注意理解线程的生命周期。恩,就这些问题。
明天来回顾反射,和写我的毕业设计开题报告。
原文地址:http://blog.csdn.net/sloverpeng/article/details/44208405