表A: 演示高级线程方法的伪代码
class ProdCons
{
class List
{
public synchronized boolean add(Object o)
{}
public synchronized boleanremove (Object o)
{}
}
List data = new List();
ProdThread producer = null;
ConsThread consumer = null;
ProdCons()
{
producer = new ProdThread(this);
consumer = new ConsThread(this);
producerstart();
consumerstart();
}
}
消费者和生产者的类请见表B和表C
表B: Class ConsThread
class ConsThread extends Thread
{
ProdCons parent;
ConsThread(ProdCons parent)
{
thisparent = parent;
}
public synchronized void canConsume()
{
notify();
}
public void run()
{
boolean consumed;
do
{
synchronized(this)
{
try { wait();
}
catch (Exception e) { ; }
}
do
{
String str = (String)parentlistremove();
if ( null == str)
{
consumed = false;
break;
}
consumed = true;
Systemoutprintln(Consumer=>consumed + str);
}
while ( true );
}
while (consumed);
}
表C: Class ProdThread
class ProdThread extends Thread
{
ProdCons parent;
ProdThread(ProdCons parent)
{
thisparent = parent;
}
public void run()
{
for ( int i = ; i < ; i++)
{
String str = new String(ImAString + i);
Systemoutprintln(Producer produced + str);
parentlistadd(str);
parentconsumercanConsume();
}
parentconsumercanConsume();
}
}
注意notify和wait两个API都必须位于同步化(synchronized)的方法中或者代码块中!
线程和Sun JDK
线程提供了一项很有价值的服务极大地增强了Java程序设计语言的功能然而目前的线程实现的确存在一些问题这些问题的存在使得Sun JDK 中线程的stop suspend和resume方法导致人们的批评
如果我们回到上面的生产者/消费者例子我们就可以更好地理解这个问题首先我们看看死锁当运行一个applet小程序时在通常的情况下两个线程运行时相安无事但是但用户点击到另外一个网页时问题出现了如果生产者正在添加一个项目到列表中最坏的情况就是消费者线程被阻塞假定小程序正在创建一个对象此时突然被挂起(suspended)其他的小程序就不能再对该数据进行更新尽管出现这样的机会不多它们的确存在有时会引起问题
线程的第二个问题有关不一致的问题再来看一下生产者/消费者的例子不难想象如果生产者线程在添加项目的过程中遇到被中止的情况可能会造成列表状态不一致如果我们全面检查现有的Java小程序的个数就不难发现问题所在
处理这个不一致的问题的最简单的方法就是派生一个新的线程类该线程类具有如下功能通过一个方法的调用可以改变其状态表D就定义了这样的一个类MyThread类可以被挂起和重新执行而无需担心MyThread类的资源会崩溃MyThread类中的方法 changeState用于暗示应该暂停停止或者重新执行线程而不同于以往的停止或者暂停线程可以向线程发出请求要求线程在合适的时候处理该请求而不是强制处理该请求因而无需向线程发出停止命令
表D: Class MyThread
public class MyThread extends Thread
{
//States the thread can be in
static final int STATE_RUNNING = ;
static final int STATE_STOP = ;
static final int STATE_SUSPEND = ;
private int currentState = STATE_RUNNING;
// The public method changeState allows
// another process to poke at that hread
// and tell it to do something when it
// next gets a chance
public final synchronized void
changeState(int newState)
{
currentState = newState;
if (STATE_RUNNING == currentState)
notify();
// Must have been suspended
}
private synchronized boolean currentState()
{
// If we where asked to suspend
// just hang out until we are
// asked to either run or stop
while ( STATE_SUSPEND == currentState)
{
try{ wait(); }
catch (Exception e) {};
}
if ( STATE_STOP == currentState )
return false;
else
return true;
}
public void run()
{
do
{
if (currentState() == false)
return; // Done
// Perform some work
}
while (true);
}
}
MyThread类的用户可以重载run方法然而用户需要检查是否有另外的类请求线程改变状态在JDK 中对线程的运行机制所做的改变是问题的症结所在线程在运行时是否出现不一致在线程关闭后是否放弃所占用的资源线程的运行是否正常这些工作都是要开发者自己来确保完成了
结论
线程功能强大而使用复杂每位Java开发者可以在很多应用场合用到线程本文中我们检查了线程的一些副作用以及线程的一些高级用法随着Sun JDK 的推出开发者们将被迫对其编写的线程对系统和其他进程的作用过程考虑得更加周到最终对于线程及其相关知识的正确理解将会有助于聪明的开发者设计出更加健壮的应用程序