`
trent_luo
  • 浏览: 43870 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

关于线程使用的实例

阅读更多
用生产者消费者模式的例子来阐述线程使用当中的一些细节问题。
import java.util.ArrayList;

public class ThreadTest {
class Plate {
private ArrayList eggs = new ArrayList();

void putEgg(Object egg) throws InterruptedException {
if(eggs.size() > 0){
wait();
}
eggs.add(egg);
System.out.println("Put an egg on the plate,Totals:"+eggs.size());
notify();
}

void getEgg() throws InterruptedException {
if (eggs.size() == 0) {
wait();
}
eggs.remove(0);
System.out.println("Take an egg from plate,Totals:" + eggs.size());
notify();

}
}

class AddThread extends Thread {
private Plate plate;
private Object egg = new Object();

public AddThread(Plate plate) {
this.plate = plate;
}

@Override
public void run() {
System.out.println("AddThread is running ...");
for (int i = 0; i < 10; i++) {
try {
plate.putEgg(egg);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

class GetThread extends Thread {
private Plate plate;

public GetThread(Plate plate) {
this.plate = plate;
}

@Override
public void run() {
System.out.println("GetThread is running...");
for (int i = 0; i < 10; i++) {
try {
plate.getEgg();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

public static void main(String[] args) throws InterruptedException {
ThreadTest obj = new ThreadTest();
Plate plate = obj.new Plate();
Thread add = new Thread(obj.new AddThread(plate),"AddThread");
Thread get = new Thread(obj.new GetThread(plate),"GetThread");
//add.run();如果用run 方法的话,等于直接调用某个线程的run方法。不会重新启动一个新的线程。线程还是在主线程中运行。应该调用start()方法
//get.run();
add.start();
get.start();
System.out.println("Running ...");
}
}

AddThread is running ...
GetThread is running...
Running ...
这三行文字的打印顺序是不固定的,随机的。因为三个线程的执行顺序是
如果用run 方法的话,等于直接调用某个线程的run方法。不会重新启动一个新的线程。线程还是在主线程中运行。应该调用start()方法

执行这个程序是会报 java.lang.IllegalMonitorStateException 的异常。因为代码中的执行 wait(),notify()方法,的线程线程,并不拥有Plate 对象的锁。一个线程想得到一个对象的锁,有三种途径:
1. 执行对象的 synchronized 实例方法。
2. 执行对象上的 synchronized 块。
3. 对于 synchronized 静态方法

修改相应代码
synchronized void  putEgg(Object egg) throws InterruptedException {
if(eggs.size() > 0){
wait();
}
eggs.add(egg);
System.out.println("Put an egg on the plate,Totals:"+eggs.size());
notify();
}

synchronized void getEgg() throws InterruptedException {
if (eggs.size() == 0) {
wait();
}
eggs.remove(0);
System.out.println("Take an egg from plate,Totals:" + eggs.size());
notify();

}
将这两个方法加上 synchronized,程序可正常运行。
如果修改main方法为

public static void main(String[] args) throws InterruptedException {
ThreadTest obj = new ThreadTest();
Plate plate1 = obj.new Plate();
Plate plate2 = obj.new Plate();
Thread add = new Thread(obj.new AddThread(plate1),"AddThread");
Thread get = new Thread(obj.new GetThread(plate2),"GetThread");
add.start();
get.start();
System.out.println("Running ...");
}
程序的运行结果是,线程将永远挂起。因为这两个线程,他们得到的对象不是同一个对象。也就是他们得到的对象锁不是同一个。当他们得到各自的对象锁,被挂起的时候。没有其他的线程在该对象锁上将他们唤醒。
修改main方法为
public static void main(String[] args) throws InterruptedException {
ThreadTest obj = new ThreadTest();
Plate plate = obj.new Plate();
Thread add = new Thread(obj.new AddThread(plate),"AddThread");
Thread get = new Thread(obj.new GetThread(plate),"GetThread");
add.start();
get.start();
add.join();
get.join();
System.out.println("Running ...");
}
加上了add.join(),get.join()方法后。 Main线程会等到两个线程死亡后,再继续执行。所以字符串 Running ... 是最后打印。
   修改代码将 取得egg 的循环次数 I 设置为 100.运行结果则是 main线程将被永久挂起。因为 getThread 循环 10次后,还在等待 取得 egg。而 putEgg已经执行完了,将不会唤醒 getThread线程。所以main 线程永远等不到 getThread 线程的死亡。
1
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics