引用
先看一个程序
package Thread;
import java.util.LinkedList;
import java.util.List;
public abstract class Workquery
{
private final List<Object> query=new LinkedList<Object>();
private boolean stopped=false;
protected Workquery()
{
System.out.println("workquery。。。。。。。。。。 ");
new workThread().start();
}
public final void enquery(Object item)
{
synchronized(query)
{
query.add(item);
query.notify();
}
}
public final void stop()
{
stopped=true;
query.notify();
}
public abstract void processItem(Object item);
class workThread extends Thread
{
public void run()
{
System.out.println("work thread is running");
while (true)
{
synchronized(query)
{
while(query.isEmpty()&&!stopped)
{
try
{
System.out.println("workThread i s wait....");
query.wait();
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(stopped)
{
return;
}
System.out.println("运行中...");
}Object workitem=query.remove(0);
processItem(workitem);//当这句也在同步块中时,
}
}
}
}
需要个子类的实现重写proceessItem运行
public class DeadLock extends Workquery
{
public final void processItem(final Object item)
{
Thread child =new Thread()
{
public void run()
{
enquery(item);
}
};
child.start();
try
{
child.join();
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String []args)
{
new DeadLock().processItem("2");
}
}
在看程序之前需要知道
死锁的条件
引用
发生死锁的四个必要条件!
1、互斥:也许线程会用到很多资源,但其中至少要有一项是不能共享的。
2、至少要有一个进程会在占用一项资源的同时还在等另一项正被其它进程所占用的资源。
3、(调度系统或其他进程)不能从进程里抢资源。所有进程都必须正常的释放资源。
4、必需要有等待的环。一个进程在一个已经被另一进程抢占了的资源,而那个进程又在等另一个被第三个进程抢占了的资源,以此类推,直到有个进程正在等被第一个进程抢占了的资源,这样就形成了瘫痪性的阻塞了。
只要满足上面的条件就有可能发生死锁的情况~所以避免上面任何一条就可以解决多线程的死琐
那么看这个程序
首先
new DeadLock().processItem("2")
会调用父类的构造函数!假设在一个包内!!
workTread线程处于等待状态!!这时child线程启动!并且enquery一个Item这时唤醒workTread!这时child释放query锁对象!
执行到
Object workitem=query.remove(0);
processItem(workitem);
这时又启动了一个线程child这时他需要获得query的写入锁!而这时workTread还在持有锁!!还没正常释放资源!!
这样造成了死锁!!
怎么解决呢
改下workThread
processItem(workitem);
移到synchronize同步块外面!!
就可以了
了解下synchronize关键字
引用
synchronized关键字的作用域有二种:
1)是某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法;
2)是某个类的范围,synchronized static aStaticMethod{}防止多个线程同时访问这个类中的synchronized static 方法。它可以对类的所有对象实例起作用。
2、除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。用法是: synchronized(this){/*区块*/},它的作用域是当前对象;
3、synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法;
因为如果上面的程序中 在同步块中吗,那么他会防止多个程序访问query这个区块!
所以放到外面就可以了!!
有没有注意在Child.start()后有个join 这个是等待线程执行完毕后!!
http://lz12366.iteye.com/blog/640480
这里有个例子帮之理解
class workThread extends Thread
{
public void run()
{
System.out.println("work thread is running");
while (true)
{
synchronized(query)
{
while(query.isEmpty()&&!stopped)
{
try
{
System.out.println("workThread i s wait....");
query.wait();
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(stopped)
{
return;
}
System.out.println("运行中...");
}
Object workitem=query.remove(0);
processItem(workitem);//当这句也在同步块中时,
}
}
}