——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-
线程间通讯:
其实就是多个线程在操作同一个资源,但是操作动作不同。
等待唤醒机制的理解:
其实就是多个在线程通讯时使用的技术手段是各个线程能有效利用资源,通过一定的手段使各个线程能有效的利用资源。而这种手段即:等待唤醒机制。
比如有两个线程,A线程向资源内存数据,B线程从资源内取数据,在线程A操作时,B线程处于wait()状态,当A操作完后,将B线程notify(),B线程取完数据后,将A唤醒,自己处于wait()状态。
wait()、sleep()有什么区别?
wait():释放资源、释放锁
sleep():释放资源不释放锁
wait()、notify、notify、All,用来操作线程为什么定义在Object类中?
1.这些方法存在于同步中。
2.使用这些方法时必须要标识所属的同步的锁。
3.锁可以是任意对象,所以任意对象调用的方法一定定义在Object类中。
使用等待唤醒机制解决经典问题:生产者与消费者问题。
/*
经典问题:生产者消费者问题
生产的物品带编号,生产一个消费一个。
如果只有一个生产者,一个消费者
使用if判断标记,notify唤醒是可以的
但是如果有多个生产者消费者
必须使用while判断标记,使用notifyAll唤醒等待中的全部线程
*/
class Resource
{
private String name;
private int count=1;//计数器
private boolean flag=false;
public synchronized void set(String name)
{
while(flag) //此处如果使用if则只判断一次
try{wait();}catch(Exception e){}
this.name=name+"------"+count++;
System.out.println(Thread.currentThread().getName()+"..."+this.name);
flag=true;
notifyAll(); //将线程池内的线程全部唤醒,如果只有一个线程调用这个方法可以只notify
}
public synchronized void out()
{
while(!flag) //此处如果使用if则只判断一次
try{wait(1000);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"______"+name);
flag=false;
notifyAll(); //将线程池内的线程全部唤醒,如果只有一个线程调用out方法可以只notify
}
}
class Producer implements Runnable
{
private Resource res;
Producer(Resource res)
{
this.res=res;
}
public void run()
{
while(true)
{
res.set("商品");
}
}
}
class Consumer implements Runnable
{
private Resource res;
Consumer(Resource res)
{
this.res=res;
}
public void run()
{
while(true)
{
res.out();
}
}
}
class ProConDemo1
{
public static void main(String[] args)
{
Resource rec=new Resource();
new Thread(new Producer(rec)).start();
new Thread(new Producer(rec)).start();
new Thread(new Consumer(rec)).start();
new Thread(new Consumer(rec)).start();
}
}
对于上面的生产者消费者问题,JDK1.5版本以后java提供了新的解决方案。出现了lock接口。将同步synchronized替换成了显示Lock操作。将Object中的wait,notify,notifyAll,替换成了Condition操作。
该Condition对象可以通过Lock锁进行获取。
import java.util.concurrent.locks.*;
class Resource
{
private String name;
private int count=1;//计数器
private boolean flag=false;
Lock lock=new ReentrantLock();
Condition condition_pro=lock.newCondition();
Condition condition_com=lock.newCondition();
public void set(String name)
{
lock.lock();
try{
while(flag)
condition_pro.await();
this.name=name+"------"+count++;
System.out.println(Thread.currentThread().getName()+"..."+this.name);
flag=true;
condition_com.signal();
}catch(Exception e){}
finally
{
lock.unlock();//释放锁的动作一定要执行
}
}
public void out()
{
lock.lock();
try
{
while(!flag) //此处如果使用if则只判断一次
condition_com.await();
System.out.println(Thread.currentThread().getName()+"______"+name);
flag=false;
condition_pro.signal();
}
catch(Exception e)
{}
finally
{
lock.unlock();
}
}
}
class Producer implements Runnable
{
private Resource res;
Producer(Resource res)
{
this.res=res;
}
public void run()
{
while(true)
{
res.set("商品");
}
}
}
class Consumer implements Runnable
{
private Resource res;
Consumer(Resource res)
{
this.res=res;
}
public void run()
{
while(true)
{
res.out();
}
}
}
class LockDemo
{
public static void main(String[] args)
{
Resource rec=new Resource();
new Thread(new Producer(rec)).start();
new Thread(new Producer(rec)).start();
new Thread(new Consumer(rec)).start();
new Thread(new Consumer(rec)).start();
}
}
注意:
1.多条语句操作同一资源时很容易发生安全问题
2.等待和唤醒用的锁必须是同一个
3.多线程操作统一资源时,很多人都容易先想到静态和单例,但是那样做都很麻烦。可以创建资源对象,将同一个资源对象作为参数传入不同线程的构造函数中,就能达到对同一资源的不同操作。
伪代码在下面:
class Resource{
Resource(){}
}
class AThread implements Runnable{
private Resource res;
Athread(Resource res)
{
this.res=res;
}
public void run(){}
}
class BThread implements Runnable{
private Resource res;
BThread(Resource res)
{
this.res=res;
}
public void run(){}
}
class Test
{
public static void main(String[] args)
{
Resource res=new Resource();
new Thread(new AThread(res)).start();
new Thread(new BThread(res)).start();
}
}