黑马程序员——JAVA基础之多线程的线程间通讯等
------- 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基础之多线程的线程间通讯等的更多相关文章
- 黑马程序员 Java基础<九>---> 多线程
ASP.Net+Android+IOS开发..Net培训.期待与您交流! 多线程 一.概述: 1.线程是什么 说到线程,我们就得先说说进程.所谓进程,就是一个正在执行(进行)中的程序,每一个进程执行都 ...
- 黑马程序员----java基础:多线程
------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ---- ...
- 黑马程序员——JAVA基础之多线程的安全问题
------- android培训.java培训.期待与您交流! ---------- 导致多线程出现问题的一个特殊的状态:就绪.具备了执行资格,但是还没有获取资源. 导致安全问题的出现的原因: 1. ...
- 黑马程序员_Java基础:多线程总结
------- android培训.java培训.期待与您交流! ---------- 一.多线程的概念 进程和线程经常会被人混淆,那是因为对它们的概念不明确.就拿我们平时使用的操作系统来说,它是多任 ...
- 黑马程序员----java基础笔记中(毕向东)
<p>------<a href="http://www.itheima.com" target="blank">Java培训.Andr ...
- 黑马程序员Java基础班+就业班课程笔记全发布(持续更新)
正在黑马学习,整理了一些课程知识点和比较重要的内容分享给大家,也是给自己拓宽一些视野,仅供大家交流学习,大家有什么更好的内容可以发给我 ,现有黑马教程2000G QQ 1481135711 这是我总 ...
- 黑马程序员----java基础笔记上(毕向东)
------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 笔记一共记录了毕向东的java基础的25天课程,分上.中.下 本片为上篇,涵盖前10天课程 1. ...
- 黑马程序员——JAVA基础之泛型和通配符
------- android培训.java培训.期待与您交流! ---------- 泛型: JDK1.5版本以后出现新特性.用于解决安全问题,是一个类型安全机制. 泛型好处: ...
- 黑马程序员——JAVA基础之简述面向对象,类,变量,匿名对象
------- android培训.java培训.期待与您交流! ---------- 面向对象: 面向对象是相对面向过程而言 面向对象和面向过程都是一种思想 面向过程 强调的是功能行为 面向对象 将 ...
随机推荐
- C++学习 之const
const在C++中很常用,在编程中也建议多使用const去告诉编译器和其他程序员某个值应该保持不变. const可以用在很多地方: (1)用在classes外部修饰global或namespace作 ...
- 红帽中出现”This system is not registered with RHN”的解决方案
原因是你的linux没有在红帽网络上注册,所以无法下载上面的软件包,替代方案可以使用centos. 下面介绍下使用centos 的流程 1.卸载rhel的默认安装的yum包查看yum包rpm -qa| ...
- 【python练习】截取网页里最新的新闻
需求: 在下面这个网页,抓取最新的新闻,按天划分. http://blog.eastmoney.com/13102551638/bloglist_0_1.html 实现方法1:使用递归 import ...
- 使用hadoop multipleOutputs对输出结果进行不一样的组织
MapReduce job中,可以使用FileInputFormat和FileOutputFormat来对输入路径和输出路径来进行设置.在输出目录中,框架自己会自动对输出文件进行命名和组织,如:par ...
- 2016 - 1- 22 NSURLConnetction --- GET请求
---恢复内容开始--- 一: 给服务器发送一个简单的GET请求 1.同步 // 发送一个GET请求给服务器 // 0.请求路径 NSURL *url = [NSURL URLWithString:@ ...
- Linux下查看每个目录所占用空间大小的命令
cd到上级目录,然后输入一条命令即可查询每个子目录所占用的空间大小 du -h --max-depth=1 可以更改--max-depth参数的值,该参数表示查询子目录的层级,当前为1层
- css 时钟
(转自:http://www.cnblogs.com/Wenwang/archive/2011/09/21/2184102.html) <!DOCTYPE html> <html l ...
- POJ2449 (k短路)
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> # ...
- 一个比较完整的Inno Setup 安装脚本
一个比较完整的Inno Setup 安装脚本,增加了对ini文件设置的功能,一个安装包常用的功能都具备了. [Setup] ; 注: AppId的值为单独标识该应用程序. ; 不要为其他安装程序使用相 ...
- 实现Magento多文件上传代码功能开发
在Magento中上传单个文件很简单,可以直接在继承的Mage_Adminhtml_Block_Widget_Form类中直接添加如下组件Field: 对于图片: $fieldset->a ...