Java基础12天 学习笔记_多线程(线程间的通信,生产消费者,等待唤醒机制,while+notifyAll,lock+condition,interrupt()+异常中改变flag值,守护,join

来源:互联网 发布:民生银行mac网银控件 编辑:程序博客网 时间:2024/05/09 16:15

01线程间的通信实例代码

 

不同的线程做不同的操作,如操作同一个资源时,一个input,一个output

资源~操作动作。

如果同步后还是发现同步失效,考虑前提: 1.是否多线程2时候同一个锁

 

操作同一个资源!需要用单例模式,或者传入相同的对象。

if (x==0) else , x= (x+1)%2

为了合理的操作这

用等待唤醒机制让输入和输出和谐的进行、

 

内存中有线程池,等待的线程都存在线程池当中。

线程池的概念:

线程池的作用:

线程池作用就是限制系统中执行线程的数量。
     根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;少了浪费了系统资源,多了造成系统拥挤效率不高。用线程池控制线程数量,其他线程排队等候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有等待进程,线程池的这一资源处于等待。当一个新任务需要运行时,如果线程池中有等待的工作线程,就可以开始运行了;否则进入等待队列。

为什么要用线程池:

1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。

2.可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService



wait() ,sleepx),一样,都会抛出异常,所以需要用try , catch处理。

还有在使用wait时也需要表明,持有锁的线程, r.wait () ------持有r锁的线程等待,因为同步会出现嵌套。



/* Day12 , 多线程间的通信同一资源,不同的对象调用, 并使用多线程。*/class Res{String name;String sex;Boolean flag=false;}class Input implements Runnable{private Res r;Input (Res r){this.r=r;}public void run(){int x=0;while (true){synchronized (r){if (r.flag){try{r.wait();}catch (Exception e){}}if (x==0){r.name="Jerry";r.sex="Boy";}else {r.name="安娜";r.sex="女";}x=(x+1)%2;r.flag = true;r.notify();}}}}class Output implements Runnable{private Res r;Output(Res r){this.r=r;}public void run(){while (true){synchronized (r){if (!r.flag){try{r.wait();}catch (Exception e){}}System.out.println("姓名"+r.name+"---性别"+r.sex);r.flag=false;r.notify();}}}}class  InputOutputDemo{public static void main(String[] args) {Res resource= new Res();Input i=new Input(resource);Output o= new Output(resource);Thread a=new Thread(i);Thread b=new Thread(o);a.start();b.start();}}

构造函数也会涉及到锁,同步,等待唤醒机制

代码经过优化,把构造函数添加this锁,同步,等待和唤醒机制。


class Res{private String name;private String sex;Boolean flag=false;public synchronized void setValue (String name, String sex){if (flag){try{this.wait();}catch (Exception e){}}this.name=name;this.sex=sex;flag=true;this.notify();}public synchronized void out(){if(!flag){try{this.wait();}catch (Exception e){}}System.out.println(name+"....."+sex);flag=false;this.notify();}}

05生产消费者例子

将计数器定义在资源中, this.name= name+"---"+count++

 

当有多个线程生产,多个线程消费时,会出现:

重复生产或者重复消费,

原因:在唤醒的时候没有判断flag并不知道前面的生产者已经生产了一次。

解决:

将原来的if判断一次,变成while判断多次。+ notifyAll();



这是最常用的方式! whileflag + notifyAll();

 

JDK 1.5后,加入了lockcondition来替代 synchronized ()

 

lock.lock()

try

{

while (flag)

condition1.await();

xxxxx

xxx

xxxxx

flag= true;

condition2.signal

 

}

 

finally

{

lock.unlock(); //lock是资源,也需要finally来释放

}

lockcondition不用嵌套,就没有死锁问题,

而且可以定义多个condition,以组为单位来唤醒对方,不会出现所有都等待。




需要interrupt()----InterruptException----在异常处理中加入 changeFlag()控制语句流程

 

线程有守护值,如果守护值为true,则在后台运行,当进程中所有的线程都是守护线程的时候虚拟机结束。

setDeamon(true)

 

 

t1.join(); ,t1要申请cpu执行权,要抢夺CPU执行权。

主线程碰到谁的Join就等谁。

 

 

优先级和Yield方法

养成习惯,数据固定的用常量,数据共享的用静态 , Thread.MAX_PRIORITY

yield,临时释放,平均使用CPU


需要interrupt()----InterruptException----在异常处理中加入 changeFlag()控制语句流程

 

线程有守护值,如果守护值为true,则在后台运行,当进程中所有的线程都是守护线程的时候虚拟机结束。

setDeamon(true)

 

 

t1.join(); ,t1要申请cpu执行权,要抢夺CPU执行权。

主线程碰到谁的Join就等谁。

 

 

优先级和Yield方法

养成习惯,数据固定的用常量,数据共享的用静态 , Thread.MAX_PRIORITY

yield,临时释放,平均使用CPU




匿名内部类就可以完成这样的操作,在同一个类中开启多线程。

或者 Runnable r= new Runnable(){覆盖run()}

new Thread(r).start();



0 0
原创粉丝点击