------- android培训java培训、期待与您交流!
----------

线程间通讯:

其实就是多个线程在操作同一个资源,但是动作不同。

wait();

在其他线程调用此对象的notify()方法或notifyAll()方法,或者超过指定的时间量前,导致当前线程等待。

当前线程必须拥有此对象监视器。

notify();

唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。

选择是任意性的,并在对实现做出决定时发生。

线程通过调用其中一个 wait 方法,在对象的监视器上等待。

notifyAll(); 

唤醒在此对象监视器上等待的所有线程。线程通过调用其中一个 wait 方法,在对象的监视器上等待。

思考1:wait ( ),notify ( ),notifyAll ( ),用来操作线程为什么定义在了Object 类中?

1,这些方法存在与同步中。

     2,使用这些方法时必须要标识所属的同步的锁。

     3,锁可以是任意对象,所以任意对象调用的方法一定定义Object类中。

因为这些方法在操作同步中线程时,都必须要标识它们所操作线程只有的锁,只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒。不可以对不同锁中的线程进行唤醒。 

 也就是说,等待和唤醒必须是同一个锁。而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中。

思考2:wait ( ) ,sleep ( ) 有什么区别?

wait ( ) : 释放cpu执行权,释放锁。

     sleep ( ) : 释放cpu执行权,不释放锁。

/**
*
* 多线程通讯示例:
* 多线程通讯就是多个线程共同操作同一个资源,但是动作不同
* 例:开启两个线程,交替输入输出两个人的名字和年龄
*
*/
public class ThreadTest
{
public static void main(String[] args)
{
Person p = new Person();
Input in = new Input(p);
Output out = new Output(p); Thread t1 = new Thread(in);
Thread t2 = new Thread(out); t1.start();
t2.start();
}
} //声明一个Person类,有两个属性,姓名和性别
class Person
{
String name;
String sex;
} //声明一个输入线程继承Runnable。传入名字和性别
class Input implements Runnable
{
private Person p; Input (Person p)
{
this.p = p;
} public void run()
{
int x = 0; while(true)
{
synchronized (p)
{
if (x==0)
{
p.name = "lilei";
p.sex = "boy";
}
else
{
p.name = "hanmeimei";
p.sex = "girl";
}
x = (1+x)%2;
}
}
}
} //声明一个输出线程的类继承Runnable,输出姓名和性别
class Output implements Runnable
{
private Person p; Output(Person p)
{
this.p = p;
} public void run()
{
while(true)
{
synchronized (p)
{
System.out.println("name: "+p.name+"-------sex: "+p.sex);
}
}
}
}

等待唤醒机制:

改进一下这个程序,让输入输出交替进行

/**
*
* 多线程通讯示例:
* 多线程通讯就是多个线程共同操作同一个资源,但是动作不同
* 例:开启两个线程,交替输入输出两个人的名字和年龄
*
*/
public class ThreadTest
{
public static void main(String[] args)
{
Person p = new Person();
Input in = new Input(p);
Output out = new Output(p); Thread t1 = new Thread(in);
Thread t2 = new Thread(out); t1.start();
t2.start();
}
} //声明一个Person类,有两个属性,姓名和性别
class Person
{
String name;
String sex;
boolean flat;
} //声明一个输入线程继承Runnable。传入名字和性别
class Input implements Runnable
{
private Person p; Input (Person p)
{
this.p = p;
} public void run()
{
int x = 0; while(true)
{
synchronized (p)
{
if (p.flat)
try{p.wait();}catch(Exception e){}
if (x==0)
{
p.name = "lilei";
p.sex = "boy";
}
else
{
p.name = "hanmeimei";
p.sex = "girl";
}
x = (1+x)%2;
p.flat = true;
p.notify();
}
}
}
} //声明一个输出线程的类继承Runnable,输出姓名和性别
class Output implements Runnable
{
private Person p; Output(Person p)
{
this.p = p;
} public void run()
{
while(true)
{
synchronized (p)
{
if (!p.flat)
try{p.wait();}catch(Exception e){}
System.out.println("name: "+p.name+"-------sex: "+p.sex);
p.flat = false;
p.notify();
}
}
}
}

发现有些数据不能被外界直接调用,具有安全隐患,所以改进如下:

/**
*
* 多线程通讯示例:
* 多线程通讯就是多个线程共同操作同一个资源,但是动作不同
* 例:开启两个线程,交替输入输出两个人的名字和年龄
*
*/
public class ThreadTest
{
public static void main(String[] args)
{
Person p = new Person();
Input in = new Input(p);
Output out = new Output(p); Thread t1 = new Thread(in);
Thread t2 = new Thread(out); t1.start();
t2.start();
}
} //声明一个Person类,有两个属性,姓名和性别
class Person
{
//私有数据,更安全
private String name;
private String sex;
private boolean flat; public synchronized void set(String name,String sex)
{
if (flat)
try{this.wait();}catch(Exception e){}
this.name = name;
this.sex = sex;
flat = true;
this.notify();
} public synchronized void out()
{
if (!flat)
try{this.wait();}catch(Exception e){}
System.out.println("name: "+name+"-------sex: "+sex);
flat = false;
this.notify();
}
} //声明一个输入线程继承Runnable。传入名字和性别
class Input implements Runnable
{
private Person p; Input (Person p)
{
this.p = p;
} public void run()
{
int x = 0; while(true)
{
if (x==0)
p.set("lilei","boy");
else
p.set("hanmeimei","girl");
x = (x+1)%2;
}
}
} //声明一个输出线程的类继承Runnable,输出姓名和性别
class Output implements Runnable
{
private Person p; Output(Person p)
{
this.p = p;
} public void run()
{
while(true)
{
p.out();
}
}
}

为什么定义notifyAll:

因为需要唤醒对方线程。

因为只用notify,容易出现只唤醒本方线程的情况。导致程序中的所有线程都等待。

/**
*
* 当出现两个以上多线程进行多线程通讯的时候,需要用的notifyAll();
* 例子:
* 生产者消费者
*
*/
public class ProCusDemo
{
public static void main(String[] args)
{
Resource r = new Resource(); Pro p = new Pro(r);
Cus c = new Cus(r); Thread t1 = new Thread(p);
Thread t2 = new Thread(p);
Thread t3 = new Thread(c);
Thread t4 = new Thread(c); t1.start();
t2.start();
t3.start();
t4.start();
}
} //声明一个资源类,赋予基本属性
class Resource
{
private String name;
private int count = 1;
private boolean flat; public synchronized void set(String name)
{
while (flat)//用while让被唤醒的线程再一次判断标记
try{wait();}catch(Exception e){}
this.name = name+"-----"+count++; System.out.println(Thread.currentThread().getName()+"---生产者---"+this.name);
flat = true;
notifyAll();
} public synchronized void out()
{
while (!flat)//用while让被唤醒的线程再一次判断标记
try{wait();}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"---消费者---"+this.name);
flat = false;
notifyAll();
}
} class Pro implements Runnable
{
private Resource r; Pro(Resource r)
{
this.r = r;
} public void run()
{
while (true)
{
r.set("商品");
}
}
} class Cus implements Runnable
{
private Resource r; Cus(Resource r)
{
this.r = r;
} public void run()
{
while (true)
{
r.out();
}
}
}

JDK1.5 中提供了多线程升级解决方案。

将同步Synchronized替换成现实Lock操作。

将Object中的wait,notify notifyAll,替换了Condition对象。

该对象可以Lock锁进行获取。

该示例中,实现了本方只唤醒对方操作。

 

Lock:替代了Synchronized 

    lock 

    unlock

    newCondition()

 

Condition:替代了Object wait notify notifyAll

    await();

    signal();

    signalAll();

<span style="font-size:14px;">import java.util.concurrent.locks.*;

class ProducerConsumerDemo2
{
public static void main(String[] args)
{
Resource r = new Resource(); Producer pro = new Producer(r);
Consumer con = new Consumer(r); Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con); t1.start();
t2.start();
t3.start();
t4.start(); }
} class Resource
{
private String name;
private int count = 1;
private boolean flag = false; private Lock lock = new ReentrantLock(); private Condition condition_pro = lock.newCondition();
private Condition condition_con = lock.newCondition(); public void set(String name)throws InterruptedException
{
lock.lock();
try
{
while(flag)
condition_pro.await();//t1,t2
this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
flag = true;
condition_con.signal();
}
finally
{
lock.unlock();//释放锁的动作一定要执行。
}
} public void out()throws InterruptedException
{
lock.lock();
try
{
while(!flag)
condition_con.await();
System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);
flag = false;
condition_pro.signal();
}
finally
{
lock.unlock();
}
}
} class Producer implements Runnable
{
private Resource res; Producer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
try
{
res.set("+商品+");
}
catch (InterruptedException e)
{
} }
}
} class Consumer implements Runnable
{
private Resource res; Consumer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
try
{
res.out();
}
catch (InterruptedException e)
{
}
}
}
}
</span>

如何停止线程:

1.  定义循环结束标记,因为线程运行代码一般都是循环,只要控制了循环即可。

     2.  注:stop方法已经过时不再使用。

stop方法已经过时,如何停止线程?



       只有一种,run方法结束。开启多线程运行,运行代码通常是循环结构。只要控制住循环,就可以让run方法结束,也就是线程结束。

       特殊情况:当线程处于了冻结状态。就不会读取到标记。那么线程就不会结束。

当没有指定的方式让冻结的线程恢复到运行状态是,这时需要对冻结进行清除。强制让线程恢复到运行状态中来。这样就可以操作标记让线程结束。使用interrupt(中断)方法。

        该方法是结束线程的冻结状态,使线程回到运行状态中来。

<span style="font-size:14px;">class StopThread implements Runnable
{
private boolean flag =true;
public synchronized 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 void changeFlag()
{
flag = false;
}
} class StopThreadDemo
{
public static void main(String[] args)
{
StopThread st = new StopThread(); Thread t1 = new Thread(st);
Thread t2 = new Thread(st); t1.start();
t2.start(); int num = 0; while(true)
{
if(num++ == 60)
{
//st.changeFlag();
t1.interrupt();
t2.interrupt();
break;
}
System.out.println(Thread.currentThread().getName()+"......."+num);
}
System.out.println("over");
}
}
</span>

守护线程:

前台线程执行完之后后台线程自动执行完,主线程是前台线程。

<span style="font-size:14px;">class StopThread implements Runnable
{
private boolean flag =true;
public synchronized 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 void changeFlag()
{
flag = false;
}
} class StopThreadDemo
{
public static void main(String[] args)
{
StopThread st = new StopThread(); Thread t1 = new Thread(st);
Thread t2 = new Thread(st); t1.setDaemon(true);
t2.setDaemon(true);
t1.start();
t2.start(); int num = 0; while(true)
{
if(num++ == 60)
{
//st.changeFlag();
//t1.interrupt();
//t2.interrupt();
break;
}
System.out.println(Thread.currentThread().getName()+"......."+num);
}
System.out.println("over");
}
}
</span>

join用法:

当A线程执行到了B线程的.join()方法时,A就会等待。等B线程都执行完,A才会执行。


 

join可以用来临时加入线程执行。

<span style="font-size:14px;">class Demo implements Runnable
{
public void run()
{
for(int x=0; x<70; x++)
{
System.out.println(Thread.currentThread().getName()+"...."+x);
}
}
} class JoinDemo
{
public static void main(String[] args) throws Exception
{
Demo d = new Demo();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();
t1.join();//此时t1线程获得执行权,主线程冻结。
t2.start(); for(int x=0; x<80; x++)
{
System.out.println("main....."+x);
}
System.out.println("over");
}
}
</span>

yield() :

可以稍微减缓程序运行,产生近似于交替运行的效果。

class Demo implements Runnable
{
public void run()
{
for(int x=0; x<70; x++)
{
System.out.println(Thread.currentThread().toString()+"....."+x);//toString()显示优先级,优先级1~10,默认5
Thread.yield();//让程序稍微暂停一下,释放执行权,产生交替运行的效果
}
}
} class JoinDemo
{
public static void main(String[] args) throws Exception
{
Demo d = new Demo();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();
//t1.setPriority(Thread.MAX_PRIORITY); 设置最大优先级
t2.start(); for(int x=0; x<80; x++)
{
System.out.println("main....."+x);
}
System.out.println("over");
}
}

------- android培训java培训、期待与您交流!
----------

黑马程序员——JAVA基础之多线程的线程间通讯等的更多相关文章

  1. 黑马程序员 Java基础<九>---> 多线程

    ASP.Net+Android+IOS开发..Net培训.期待与您交流! 多线程 一.概述: 1.线程是什么 说到线程,我们就得先说说进程.所谓进程,就是一个正在执行(进行)中的程序,每一个进程执行都 ...

  2. 黑马程序员----java基础:多线程

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ---- ...

  3. 黑马程序员——JAVA基础之多线程的安全问题

    ------- android培训.java培训.期待与您交流! ---------- 导致多线程出现问题的一个特殊的状态:就绪.具备了执行资格,但是还没有获取资源. 导致安全问题的出现的原因: 1. ...

  4. 黑马程序员_Java基础:多线程总结

    ------- android培训.java培训.期待与您交流! ---------- 一.多线程的概念 进程和线程经常会被人混淆,那是因为对它们的概念不明确.就拿我们平时使用的操作系统来说,它是多任 ...

  5. 黑马程序员----java基础笔记中(毕向东)

    <p>------<a href="http://www.itheima.com" target="blank">Java培训.Andr ...

  6. 黑马程序员Java基础班+就业班课程笔记全发布(持续更新)

    正在黑马学习,整理了一些课程知识点和比较重要的内容分享给大家,也是给自己拓宽一些视野,仅供大家交流学习,大家有什么更好的内容可以发给我 ,现有黑马教程2000G  QQ 1481135711 这是我总 ...

  7. 黑马程序员----java基础笔记上(毕向东)

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 笔记一共记录了毕向东的java基础的25天课程,分上.中.下 本片为上篇,涵盖前10天课程 1. ...

  8. 黑马程序员——JAVA基础之泛型和通配符

    ------- android培训.java培训.期待与您交流! ---------- 泛型:            JDK1.5版本以后出现新特性.用于解决安全问题,是一个类型安全机制. 泛型好处: ...

  9. 黑马程序员——JAVA基础之简述面向对象,类,变量,匿名对象

    ------- android培训.java培训.期待与您交流! ---------- 面向对象: 面向对象是相对面向过程而言 面向对象和面向过程都是一种思想 面向过程 强调的是功能行为 面向对象 将 ...

随机推荐

  1. C++学习 之const

    const在C++中很常用,在编程中也建议多使用const去告诉编译器和其他程序员某个值应该保持不变. const可以用在很多地方: (1)用在classes外部修饰global或namespace作 ...

  2. 红帽中出现”This system is not registered with RHN”的解决方案

    原因是你的linux没有在红帽网络上注册,所以无法下载上面的软件包,替代方案可以使用centos. 下面介绍下使用centos 的流程 1.卸载rhel的默认安装的yum包查看yum包rpm -qa| ...

  3. 【python练习】截取网页里最新的新闻

    需求: 在下面这个网页,抓取最新的新闻,按天划分. http://blog.eastmoney.com/13102551638/bloglist_0_1.html 实现方法1:使用递归 import ...

  4. 使用hadoop multipleOutputs对输出结果进行不一样的组织

    MapReduce job中,可以使用FileInputFormat和FileOutputFormat来对输入路径和输出路径来进行设置.在输出目录中,框架自己会自动对输出文件进行命名和组织,如:par ...

  5. 2016 - 1- 22 NSURLConnetction --- GET请求

    ---恢复内容开始--- 一: 给服务器发送一个简单的GET请求 1.同步 // 发送一个GET请求给服务器 // 0.请求路径 NSURL *url = [NSURL URLWithString:@ ...

  6. Linux下查看每个目录所占用空间大小的命令

    cd到上级目录,然后输入一条命令即可查询每个子目录所占用的空间大小 du -h --max-depth=1 可以更改--max-depth参数的值,该参数表示查询子目录的层级,当前为1层

  7. css 时钟

    (转自:http://www.cnblogs.com/Wenwang/archive/2011/09/21/2184102.html) <!DOCTYPE html> <html l ...

  8. POJ2449 (k短路)

    #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> # ...

  9. 一个比较完整的Inno Setup 安装脚本

    一个比较完整的Inno Setup 安装脚本,增加了对ini文件设置的功能,一个安装包常用的功能都具备了. [Setup] ; 注: AppId的值为单独标识该应用程序. ; 不要为其他安装程序使用相 ...

  10. 实现Magento多文件上传代码功能开发

    在Magento中上传单个文件很简单,可以直接在继承的Mage_Adminhtml_Block_Widget_Form类中直接添加如下组件Field:  对于图片:   $fieldset->a ...