等待唤醒机制
等待唤醒机制同样是为了解决多线程安全性问题。比如,解决消费数目多余生产数目。
1. wait(), notify(), notifyAll()
都出现在同步中,因为要对持有监视器(锁)的线程操作,而只有同步中才有锁。
2. 被等待(wait())线程,被同一个锁上的notify()唤醒。
3. 锁可以是任意对象,可以被任意对象(锁)调用的方法定义在Object类中
4. 程序示例:
classPersonalInfo//资源
{
private String name;
private String sex;
private boolean flag = false;//资源空间需要标记,生产者消费者的例子
public synchronized void setInfo(Stringname, String sex)//同步函数
{
if(this.flag)
{
try{ this.wait();}//等待
catch(Exception e){}
}
this.name = name;
this.sex = sex;
this.flag = true;
this.notify();
}
public synchronized void getInfo()
{
if(!this.flag)
{
try{ this.wait();}//唤醒
catch(Exception e){}
}
System.out.println(name+"---------"+sex);
this.flag = false;
this.notify();
}
}
classInPut implements Runnable//创建输入继承的类
{
private PersonalInfo pf;
InPut(PersonalInfo pf)
{
this.pf = pf;
}
public void run()
{
int order = 0;
while(true)
{
if(0 == order)
{
pf.setInfo("ff","man");
}
else
{
pf.setInfo("hh","woman");
}
order = (order +1)%2;
}
}
}
classOutPut implements Runnable//创建输出线程的类
{
private PersonalInfo pf;
OutPut(PersonalInfo pf)
{
this.pf = pf;
}
public void run()
{
while(true)
{
pf.getInfo();
}
}
}
publicclass WaitNotify
{
public static void main(String[] args)
{
PersonalInfo pf = newPersonalInfo();
new Thread(newInPut(pf)).start();
new Thread(newOutPut(pf)).start();
}
}
其中,wait()与sleep()的区别是:前者释放cpu执行权,释放锁;后者释放cpu执行权,不释放锁。
5. 当生产者跟消费者都不止一个时,我们可以采用notifyAll()
classGoods
{
private String name;
private int num = 200;
private boolean flag = false;
public synchronized void setInfo(Stringname)
{
if(0 < this.num)
{
while(flag)
{
try{this.wait(); }
catch(Exceptione){}
}
this.name =name+"----"+num--;
System.out.println(Thread.currentThread().getName()+ "----生产者----" + this.name);
this.flag = true;
this.notifyAll();//线程池中的线程全部唤醒。
}
}
public synchronized void getInfo()
{
while(!flag)//此处需要用到while,循环判断
{
try{ this.wait(); }
catch(Exception e){}
}
System.out.println(Thread.currentThread().getName()+ "----消费者----" + this.name);
this.flag = false;
this.notifyAll();//全部唤醒!主要是唤醒对面,以防进程全部进入wait状态
}
}
classProducer implements Runnable//创建生产者线程
{
private Goods apple;
Producer(Goods fruit)//有什么用啊?
{
apple = fruit;
}
public void run()
{
while(true)
apple.setInfo("苹果");
}
}
classConsumer implements Runnable
{
private Goods apple;
Consumer(Goods fruit)
{
apple = fruit;
}
public void run()
{
while(true)
{
apple.getInfo();
}
}
}
classProducerConsumer
{
public static void main(String[] args)
{
Goods fushi = new Goods();
Producer p1 = newProducer(fushi);
Producer p2 = new Producer(fushi);
Consumer c1 = newConsumer(fushi);
Consumer c2 = newConsumer(fushi);
Thread tp1 = new Thread(p1,"famer1");
Thread tp2 = new Thread(p2,"famer2");
Thread tc1 = new Thread(c1,"buyer1");
Thread tc2 = new Thread(c2,"buyer2");
tp1.start();
tp2.start();
tc1.start();
tc2.start();
}
}
上面程序,在JDK5.0中提供了多线程升级解决方案:
1) 将同步synchronized替换成了显式Lock操作
2) 将Object中的wait,notify,notifyAll替换成了Condition对象的await,signal
该对象可以通过Lock锁进行获取
3) 它实现本方置唤醒对方的操作
importjava.util.concurrent.locks.*;//导入包
classGoods
{
private String name;
private int num = 200;
private boolean flag = false;
private Lock lock = newReentrantLock();
private Condition condition_pro =lock.newCondition();
private Condition condition_con =lock.newCondition();
public void setInfo(String name) throwsInterruptedException//因为没写catch
{
lock.lock();
try
{
while(flag)
{
condition_pro.await();
}
this.name =name+"----"+num--;
System.out.println(Thread.currentThread().getName()+ "----生产者----" + this.name);
this.flag = true;
condition_con.signal();
}
finally
{
lock.unlock();
}
}
public void getInfo()throwsInterruptedException
{
try
{
while(!flag)//此处需要用到while,循环判断
{
condition_con.await();
}
System.out.println(Thread.currentThread().getName()+ "----消费者----" + this.name);
this.flag = false;
condition_pro.signal();
}
finally
{
lock.unlock();
}
}
}
classProducer implements Runnable//创建线程
{
private Goods apple;
Producer(Goods apple_ipad)//有什么用啊?
{
apple = apple_ipad;
}
public void run()
{
while(true)
{
try
{
apple.setInfo("苹果");
}
catch(InterruptedException e)
{
}
}
}
}
classConsumer implements Runnable
{
private Goods apple;
Consumer(Goods apple_ipad)
{
apple = apple_ipad;
}
public void run()
{
while(true)
{
try
{
apple.getInfo();
}
catch(InterruptedException e)
{
}
}
}
}
classProducerConsumer2
{
public static void main(String[] args)
{
Goods ipad4 = new Goods();
Producer p = newProducer(ipad4);
Consumer c = newConsumer(ipad4);
Thread tp1 = new Thread( p,"factory1");
Thread tp2 = new Thread( p,"factory2");
Thread tc1 = new Thread(c,"buyer1");
Thread tc2 = new Thread(c, "buyer2");
tp1.start();
tp2.start();
tc1.start();
tc2.start();
}
}
停止线程
开启多线程运行,运行代码通常是循环结构。因此,只要控制住循环,也就是让线程结束。
class StopThread implements Runnable
{
privateboolean flag = true;
publicvoid run()
{
while(flag)
{
System.out.println(Thread.currentThread().getName()+".....run");
}
}
publicvoid changeFlag()//改变标记的方法
{
flag= false;
}
}
public class StopThreadTest
{
publicstatic void main(String[] args)
{
StopThreadst = new StopThread();
Threadt1 = new Thread(st);
Threadt2 = new Thread(st);
t1.start();
t2.start();
intnum = 0;//静态中不能私有化
while(true){
if(60< num++)
{
st.changeFlag();
break;
}
System.out.println(Thread.currentThread().getName()+"....."+num);
}
}
}
特殊情况:(同步时)当线程处于了冻结状态,就不会读取到标记,线程也就不会结束。
当没有指定的方式让冻结的线程恢复到运行状态时,需要对冻结进行清除。强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。
Thread类提供了该方法interrupt()
class StopThread implements Runnable
{
privateboolean flag = true;
publicsynchronized void run()
{
while(flag)
{
try
{
wait();
}
catch(InterruptedException e)
{
System.out.println(Thread.currentThread().getName()+".....Exception");
flag= false; //在异常处理中改变标记
}
System.out.println(Thread.currentThread().getName()+".....run");
}
}
}
public class StopThreadTest2
{
publicstatic void main(String[] args)
{
StopThreadst = new StopThread();
Threadt1 = new Thread(st);
Threadt2 = new Thread(st);
t1.start();
t2.start();
intnum = 0;//静态中不能私有化
while(true){
if(60< num++)
{
t1.interrupt();//中断,强制清除冻结状态
t2.interrupt();
break;
}
System.out.println(Thread.currentThread().getName()+"....."+num);
}
System.out.println("gameover");
}
}
join
当A线程执行到了B线程的join()方法时,A就会等待,等B线程都执行完,A才会执行
join可以用来临时加入线程执行
class ForJoin implements Runnable
{
publicvoid run()
{
for(intx = 0; x < 70; x++)
{
System.out.println(Thread.currentThread().getName()+"...."+x);
}
}
}
public class JoinTest
{
publicstatic void main(String[] args) throws Exception
{
ForJoinjoin = new ForJoin();
Threadt1 = new Thread(join);
Threadt2 = new Thread(join);
t1.start();
t1.join();
t2.start();
for(intx = 0; x < 80; x++)
{
System.out.println(Thread.currentThread().getName()+"......"+x);
}
System.out.println("over");
}
}