Java学习笔记(多线程_2)
2015-11-30 18:37
537 查看
15 多线程
15.3 多线程间通信
15.3.1 线程间通信方法
多个线程在操作统一资源,但操作的动作不同。等待唤醒机制:
例1:
class Res{ String name; String sex; boolean flag = false; } class Input implements Runnable{ Res r = new Res(); Input(Res r){ this.r = r; } public void run(){ int x = 0; while(true){ synchronized(r){//输入和输出采用同一个锁 if(r.flag){ try { r.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } if(x==0){ r.name = "李雷"; r.sex = "男"; }else{ r.name = "韩梅梅"; r.sex = "女"; } x = (x+1)%2; r.flag = true; r.notify(); } } } } class Output implements Runnable{ Res r = new Res(); Output(Res r){ this.r = r; } public void run() { while(true){ synchronized(r){ if(!r.flag){ try { r.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(r.name+"..."+r.sex); r.flag= false; r.notify(); } } } } public class InputOutputDemo { public static void main(String[] args) { Res r = new Res(); Input in = new Input(r); Output out = new Output(r); Thread t1 = new Thread(in); Thread t2 = new Thread(out); t1.start(); t2.start(); } }
运行结果:
![](http://i12.tietuku.com/61f61459b168daca.jpg)
上述代码中输入一个输出一个的机理:等待唤醒机制。
多线程加了同步依然不安全需检查是否满足以下三个条件:
是否存在两个以上线程;
两个线程是否均同步;
是否应用同一个锁,必须用同一锁。
wait()、notify()和notifyAll()都是用在同步中,因为都需要持有锁(监视器monitor)的线程操作,而只有同步中才有锁。
等待和唤醒必须用同一个锁,锁可以用任意Object对象,所以可以被任意对象调用的方法定义Object类中。
例2(例1优化):
class Res{ private String name; private String sex; private boolean flag = false; public synchronized void set(String name,String sex){ if(flag) try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } this.name = name; this.sex = sex; this.flag = true; this.notify(); } public synchronized void out(){ if(!this.flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(name+"..."+sex); this.flag= false; this.notify(); } } class Input implements Runnable{ Res r = new Res(); Input(Res r){ this.r = r; } public void run(){ int x = 0; while(true){ if(x==0){ r.set("李雷", "男"); }else{ r.set("韩梅梅", "女"); } x = (x+1)%2; } } } class Output implements Runnable{ Res r = new Res(); Output(Res r){ this.r = r; } public void run() { while(true){ r.out(); } } } public class InputOutputDemo { public static void main(String[] args) { Res r = new Res(); Thread t1 = new Thread(new Input(r)); Thread t2 = new Thread(new Output(r)); t1.start(); t2.start(); } }
两个对象多个线程问题:
class Res{ private String name; private String sex; private boolean flag = false; private int count = 1; public synchronized void set(String name,String sex){ while(flag) try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } this.name = name+count; this.sex = sex; count++; System.out.println("设置"+this.name+"..."+sex); this.flag = true; this.notifyAll();//需全部唤醒,否则按等待顺序下一个还是set,会覆盖之前的set } public synchronized void out(){ while(!this.flag){//由于存在多个线程,每次拿到锁都必须判断 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("输出..."+name+"..."+sex); this.flag= false; this.notifyAll(); } } class Input implements Runnable{ Res r = new Res(); Input(Res r){ this.r = r; } public void run(){ int x = 0; while(true){ if(x==0){ r.set("李雷", "男"); }else{ r.set("韩梅梅", "女"); } x = (x+1)%2; } } } class Output implements Runnable{ Res r = new Res(); Output(Res r){ this.r = r; } public void run() { while(true){ r.out(); } } } public class InputOutputDemo { public static void main(String[] args) { Res r = new Res(); Thread t1 = new Thread(new Input(r)); Thread t2 = new Thread(new Input(r)); Thread t3 = new Thread(new Output(r)); Thread t4 = new Thread(new Output(r)); t1.start(); t2.start(); t3.start(); t4.start(); } }
运行结果:
![](http://i5.tietuku.com/1bc32135d9acdbc1.jpg)
注意:
while判断和notify会导致死锁出现。
15.3.2 JDK1.5特性
Jdk1.5中将同步和锁封装为对象,并将操作锁的隐式方式定义到该对象中,将隐式动作变为显示动作。同步中synchronized替换为了Lock,Condition 替代了 Object 监视器方法的使用。
Lock接口可以在一个锁上加上多组监视器。
Condition接口:出现替代了Object中的wait、notify、notifyAll方法。将这些监视器方法单独进行了封装,变成Condition监视器对象,可以任意锁进行组合。
Condition接口中的await方法对应于Object中的wait方法。
Condition接口中的signal方法对应于Object中的notify方法。
Condition接口中的signalAll方法对应于Object中的notifyAll方法。
import java.util.concurrent.locks.*; class Res{ private String name; private String sex; private boolean flag = false; private int count = 1; //创建一个锁对象 private Lock lock = new ReentrantLock(); //通过已有锁获取两组监视器,一组监视设置函数,一组监视输出函数 private Condition con_set = lock.newCondition(); private Condition con_out = lock.newCondition(); public void set(String name,String sex) throws InterruptedException{ lock.lock(); try{ while(flag) con_set.await(); this.name = name+count++; this.sex = sex; System.out.println("设置"+this.name+"..."+sex); flag = true; con_out.signalAll(); }finally{ lock.unlock(); } } public void out() throws InterruptedException{ lock.lock(); try{ while(!flag){//由于存在多个线程,每次拿到锁都必须判断 con_out.await(); } System.out.println("输出..."+name+"..."+sex); flag= false; con_set.signalAll(); }finally{ lock.unlock(); } } } class Input implements Runnable{ Res r = new Res(); Input(Res r){ this.r = r; } public void run(){ int x = 0; while(true){ if(x==0){ try { r.set("李雷", "男"); } catch (InterruptedException e) { e.printStackTrace(); } }else{ try { r.set("韩梅梅", "女"); } catch (InterruptedException e) { e.printStackTrace(); } } x = (x+1)%2; } } } class Output implements Runnable{ Res r = new Res(); Output(Res r){ this.r = r; } public void run() { while(true){ try { r.out(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } public class InputOutputDemo { public static void main(String[] args) { Res r = new Res(); Input in = new Input(r); Output out = new Output(r); Thread t1 = new Thread(in); Thread t2 = new Thread(in); Thread t3 = new Thread(out); Thread t4 = new Thread(out); t1.start(); t2.start(); t3.start(); t4.start(); } }
运行结果:
![](http://i5.tietuku.com/5fbe2efc89fee2a5.jpg)
15.3.3 线程停止
开启多线程通常为循环结构,只要控制循环,就可以让run方法结束,即线程结束。特殊情况:
线程处于冻结状态,无法读取标记,程序无法结束。
可以使用Thread中的interrupt()方法将线程从冻结强制恢复至运行状态,按api中的描述:
“如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException。”
此时会抛出InterruptedException异常,则进行相应处理。
public 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){ t1.interrupt(); t2.interrupt(); break; } System.out.println(Thread.currentThread().getName()+"..."+num); } System.out.println("over"); } } 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; } }
运行结果:
![](http://i5.tietuku.com/e3b935d7ae126367.jpg)
15.3.4 其他方法
setDaemon()方法:![](http://i12.tietuku.com/377a9985932859aa.jpg)
public 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){ break; } System.out.println(Thread.currentThread().getName()+"..."+num); } System.out.println("over"); } } 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"); } } }
运行结果:
![](http://i5.tietuku.com/03dfdc6181f8602c.jpg)
ps:作为守护线程,主线程停止,守护线程也停止。
yield方法
public static void yield()
暂停当前正在执行的线程对象,并执行其他线程。
setPriority方法
public final void setPriority(int newPriority)
更改线程的优先级。
首先调用线程的 checkAccess 方法,且不带任何参数。这可能抛出 SecurityException。
在其他情况下,线程优先级被设定为指定的 newPriority 和该线程的线程组的最大允许优先级相比较小的一个。
相关文章推荐
- JAVA获取图片大小和尺寸
- spring启用线程空指针异常
- Java进阶05 多线程
- java实现摄像头调用,处理视频流
- spark 中的RDD编程 -以下基于Java api
- spring配置各层所在的位置
- maven出现JAVA_HOME is set to an invalid directory.
- Java Servlet 技术简介
- 个人学习Java的真实经验!
- java获取最新地区
- 关于REST
- java byte[] 转图片 在jsp页面显示
- 在 Java 中应用设计模式 -- Singleton
- openstack-java-sdk maven 工程环境搭建及编译
- Date类型的实体类属性中,Date必须是Java.util.Date,而不能是Java.sql.Date
- 第二章 Spring MVC入门
- Java新手之路——Day03 Java语言基础组成_数据类型
- JavaEE_Mybatis_SpringMVC_Mybatis_lesson9_引用SQL片段
- Java基础1
- Spring学习之整合Struts2