------- 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++ primer的第二章的主要内容

    这第二章主要是介绍了C++中基本的内置数据类型:整型与浮点型.介绍了什么是变量的过程中了解到了左值与右值的概念.左值是可以出现在赋值语句的左边或者右边,也就是说可以放在等号的左右两边,而右值只能是出现 ...

  2. 对比学习UIKit和AppKit--入门级

    UIKit是用来开发iOS的应用的,AppKit是用来开发Mac应用的,在使用过程中他们很相似,可是又有很多不同之处,通过对比分析它们的几个核心对象,可以避免混淆. UIKit和AppKit都有一个A ...

  3. 转:115个Java面试题和答案——终极列表(上)

    转自:http://www.importnew.com/10980.html 本文我们将要讨论Java面试中的各种不同类型的面试题,它们可以让雇主测试应聘者的Java和通用的面向对象编程的能力.下面的 ...

  4. poj1014 dp 多重背包

    //Accepted 624 KB 16 ms //dp 背包 多重背包 #include <cstdio> #include <cstring> #include <i ...

  5. Ubuntu 14.10 下sed命令详解

    简介 sed 是一种在线编辑器,它一次处理一行内容.处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的 ...

  6. AFNnetworking入门

    AFNetworking官网入门教程简单翻译,学习 AFNetworking 是一个能够快速使用的ios和mac os x下的网络框架,它是构建在Foundation URL Loading Syst ...

  7. 《view programming guide for iOS 》之可以使用动画效果的属性

    frame—Use this to animate position and size changes for the view.  ,框架,可以视图动态改变大小和位置 bounds—Use this ...

  8. Juniper SRX防火墙-NAT学习笔记!

    Junos NAT第一部分:SRX NAT介绍第二部分:Source NAT:Interface NAT第三部分:Source NAT:Address Pools第四部分:Destination NA ...

  9. WPF Step By Step 自定义模板

    WPF Step By Step 自定义模板 回顾 上一篇,我们简单介绍了几个基本的控件,本节我们将讲解每个控件的样式的自定义和数据模板的自定义,我们会结合项目中的具体的要求和场景来分析,给出我们实现 ...

  10. Windows Server 2008 R2: 创建任务计划

    task Scheduler 在业务复杂的应用程序中,有时候会要求一个或者多个任务在一定的时间或者一定的时间间隔内计划进行,比如定时备份或同步数据库,定时发送电子邮件等. 创建一个任务计划: 开始St ...