------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
七、线程间通信线程间通信概念:多线程在操作同一资源但是操作动作不一样。
等待唤醒机制涉及的方法:
wait:将同步中的线程处于冻结状态。释放了执行权和资格。同时将线程对象储存到了线程池中。
notify:唤醒线程池中某一个等待线程。
notifyAll:唤醒线程池中所有线程。
注意:
这些方法必须定义在同步中,因为这些方法是操作线程的方法。
这些方法必须要标识所属的锁。
为什么要定义notifyAll?
因为在需要唤醒对方线程时,如果只使用notify容易出现只唤醒本方线程的情况,导致程序中的所有线程都在等待。
为什么操作线程的方法wait、notify、notifyAll定义在了Object类中?
因为这些方法是监视器的方法,监视器其实就是锁。锁可以是任意对象,那么能被任意对象调用的方法一定定义在Object中
wait和sleep的区别
wait:可以指定时间也可以不指定时间。不指定时间,只能由对应的notify或者notifyAll来唤醒。
sleep:必须指定时间。
wait:线程会释放执行权,而且线程会释放锁。
sleep:线程会释放执行权,但是不会释放锁。
//生产者和消费者问题,一个线程存入姓名和性别,另一个线程打印存入的姓名和性别
class Resource
//定义一个用于存储和取出的资源
{
private String name;
private String sex;
private booean flag=false;
<span style="white-space:pre"> </span>//等待唤醒机制
public synchronized void set(String name,String sex)
{
if(flag)
try
{
this.wait();//等待
}
catch (InterruptedException e)
{
}
this.name = name
this.sex = sex
flag = true;
this.notify();//唤醒
}
public synchronized void out()
{
if(!flag)
try
{
this.wait();//等待
}
catch (InterruptedException e)
{
}
System.out.println(name+"....."+sex);
flag = false;
this.notify();//唤醒
}
}
//输入线程
class Input implements Runnable
{
private Rseource r;
Input(Resource)
{
this.r = r;
}
public void run()//复写run方法
{
int x = 0;
while(true)
{
if(x == 0)
{
r.set("mike","男");
}
else
{
r.set("lili","女");
}
x=(x+1)%2;//依次输入男女
}
}
}
//输出线程
class Output implements Runnable
{
private Resource r;
Output(Respurce r)
{
this.r = r;
}
public void run()//复写run方法
{
while(true)
{
r.out();
}
}
}
class
{
public static void main(String[] args)
{
Resource r = new Resource();//将类实例化
new Thread(new Input(r)).start();//创建并开启线程
new Thread(new Output(r)).start();
}
}
八、生产者和消费者JDK1.5升级解决方案
将同步synchronized替换成显示的Lock操作。将Object中wait,notify,notifyAll,替换成了Condition对象。该Condition对象可以通过Lock锁进行获取,并支持多个相关的Condition对象。
Condition接口中的await方法对应于Object中的wait方法。
Condition接口中的signal方法对应于Object中的notify方法。
Condition接口中的signalAll方法对应于Object中的notifyAll方法。
利用JDK1.5新特性完善多生产者和多消费者问题代码如下:
import java.util.concurrent.locks.*;
class Resource{
private String name ;
private int count = 1;
private boolean flag = false;
Lock lock = new ReentrantLock();//创建一个锁对象
Condition con = lock .newCondition(); //通过已有的锁获取该锁上的监视器对象
//通过已有的锁获取两组监视器,分别用来控制生产者和消费者的等待唤醒机制。
Condition producer_con = lock .newCondition();
Condition consumer_con = lock .newCondition();
public void set(String name)
{
lock.lock();
try{
while(flag )//重复判断标识,确认是否生产
try
{
producer_con.await();
}
catch(InterruptedException e){}
this.name = name + count;
count++;
System.out.println(Thread.currentThread().getName() + "...生产者..." + this. name);
flag = true ;//控制生产/消费标识
consumer_con.signalAll();
}
finally
{
lock.unlock();//一定要关闭资源所以使用finally方法解锁
}
}
public void out()
{
lock.lock();
try{
while(!flag )//重复判断标识,确认是否消费
try
{
consumer_con.await();
}
catch(InterruptedException e){}
flag = false ;//控制生产/消费标识
producer_con.signal();
System.out.println(Thread.currentThread().getName() + "...消费者..." + this. name);
}
finally
{
lock.unlock();//一定要关闭资源所以使用finally方法解锁
}
}
}
//生产者线程
class Producer implements Runnable{
private Resource r ;
Producer(Resource r){
this.r = r;
}
public void run(){ //复写run方法
while(true ){
r.set("商品");
}
}
}
//消费者线程
class Consumer implements Runnable{
private Resource r ;
Consumer(Resource r){
this.r = r;
}
public void run(){ //复写run方法
while(true ){
r.out();
}
}
}
class ProducerConsumerDemo {
public static void main(String[] args){
//将类实例化
Resource r = new Resource();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
//创建多线程
Thread t0 = new Thread(pro);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(con);
Thread t3 = new Thread(con);
//启动线程
t0.start();
t1.start();
t2.start();
t3.start();
}
}
九、停止线程
stop方法已经过时
任务中都会有循环结构,只要控制住循环就可以结束任务。控制循环通常就用定义标记来完成。
在while循环中通常要判断标志flag。代码如下
public void run()
{
while(flag)
{
System.out.println(Thread.currentThread().getName()+"....run");
}
}
如果线程处于冻结状态无法读取flag如何结束?
可以使用interrupt()方法将线程从冻结状态强制恢复到运行状态中来,让线程具备CPU的执行资格。
强制动作会发生InterruptedException,一定要记得处理。
十、线程的其他方法
守护线程
使用setDaemon方法将线程设置为守护线程,该方法必须在启动线程前调用。
join方法
临时加入一个线程的时候可以使用join方法
当A线程执行到B线程的join方式。A线程处于冻结状态,释放了执行权,B开始执行。只有当B线程运行结束后A才会从冻结状态恢复到运行状态执行。
yield方法
暂停当前正在执行的线程对象并执行其他线程
setPriority()方法用来设置优先级
MAX_PRIORITY 最高优先级10
MIN_PRIORITY 最低优先级1
NORM_PRIORITY 分配给线程的默认优先级