自学 java 笔记 day12(多线程)

来源:互联网 发布:股票网络销售怎么做 编辑:程序博客网 时间:2024/06/05 19:10

知识点:线程间通信及安全问题、等待唤醒、线程间通信-生产者消费者、停止线程、守护线程、Join方法、优先级&yield方法



线程间通信


既:多个线程在处理同一资源,但任务不同


生产者消费者具体情况问题:

有一个数据存储空间,划分为两部分,一部分用于存储人的姓名,另一部分用于存储人的性别;

我们的应用包含两个线程,一个线程不停向数据存储空间添加数据(生产者),另一个线程从数据空间取出数据(消费者);

因为线程的不确定性,存在于以下两种情况:

*若生产者线程刚向存储空间添加了人的姓名还没添加人的性别,CPU就切换到了消费者线程,消费者线程把姓名和上一个人的性别联系到一起;

*生产者放了若干数据,消费者才开始取数据,或者是消费者取完一个数据,还没等到生产者放入新的数据,又重复的取出已取过的数据;




wait():让当前线程放弃监视器进入等待,直到其他线程调用同一个监视器并调用notify()或notifyAll()为止。

notify():唤醒在同一对象监听器中调用wait方法的任意一个线程。

notifyAll():唤醒在同一对象监听器中调用wait方法的所有线程。


wait 和 sleep 区别?


1,wait可以指定时间也可以不指定。
   sleep必须指定时间。


2,在同步中时,对cpu的执行权和锁的处理不同。
wait:释放执行权,释放锁。
sleep:释放执行权,不释放锁。

 

这三个方法只能让同步监听器调用:

在同步方法中:      this 调用

在同步代码块中:  ()填写的对象 调用


wait()、notify()、notifyAll(),这三个方法属于Object 不属于 Thread,这三个方法必须由同步监视对象来调用,两种情况:

              1.synchronized修饰的方法,因为该类的默认实例(this)就是同步监视器,所以可以在同步方法中调用这三个方法;

              2.synchronized修饰的同步代码块,同步监视器是括号里的对象,所以必须使用该对象调用这三个方法;


可要是我们使用的是Lock对象来保证同步的,系统中不存在隐式的同步监视器对象,那么就不能使用者三个方法了,那该咋办呢?

              此时,Lock代替了同步方法或同步代码块,Condition代替了同步监视器的功能;

              Condition对象通过Lock对象的newCondition()方法创建;

              里面方法包括:

                  await(): 等价于同步监听器的wait()方法;

                  signal(): 等价于同步监听器的notify()方法;

                  signalAll(): 等价于同步监听器的notifyAll()方法;

/*等待/唤醒机制。 涉及的方法:1,wait(): 让线程处于冻结状态,被wait的线程会被存储到线程池中。2,notify():唤醒线程池中一个线程(任意).3,notifyAll():唤醒线程池中的所有线程。这些方法都必须定义在同步中。因为这些方法是用于操作线程状态的方法。必须要明确到底操作的是哪个锁上的线程。为什么操作线程的方法wait notify notifyAll定义在了Object类中? 因为这些方法是监视器的方法。监视器其实就是锁。锁可以是任意的对象,任意的对象调用的方式一定定义在Object类中。*///资源class Resource{String name;String sex;boolean flag = false;}//输入class Input implements Runnable{Resource r ;//Object obj = new Object();Input(Resource r){this.r = r;}public void run(){int x = 0;while(true){synchronized(r){if(r.flag)try{r.wait();}catch(InterruptedException e){}if(x==0){r.name = "mike";r.sex = "nan";}else{r.name = "丽丽";r.sex = "女女女女女女";}r.flag = true;r.notify();}x = (x+1)%2;}}}//输出class Output implements Runnable{Resource r;//Object obj = new Object();Output(Resource r){this.r = r;}public void run(){while(true){synchronized(r){if(!r.flag)try{r.wait();}catch(InterruptedException e){}System.out.println(r.name+"....."+r.sex);r.flag = false;r.notify();}}}}class  ResourceDemo2{public static void main(String[] args) {//创建资源。Resource r = new Resource();//创建任务。Input in = new Input(r);Output out = new Output(r);//创建线程,执行路径。Thread t1 = new Thread(in);Thread t2 = new Thread(out);//开启线程t1.start();t2.start();}}


生产者消费者示例应用


/*生产者,消费者。多生产者,多消费者的问题。if判断标记,只有一次,会导致不该运行的线程运行了。出现了数据错误的情况。while判断标记,解决了线程获取执行权后,是否要运行!notify:只能唤醒一个线程,如果本方唤醒了本方,没有意义。而且while判断标记+notify会导致死锁。notifyAll解决了本方线程一定会唤醒对方线程的问题。*/class Resource{private String name;private int count = 1;private boolean flag = false;public synchronized void set(String name)//  {while(flag)try{this.wait();}catch(InterruptedException e){}//   t1    t0this.name = name + count;//烤鸭1  烤鸭2  烤鸭3count++;//2 3 4System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);//生产烤鸭1 生产烤鸭2 生产烤鸭3flag = true;notifyAll();}public synchronized void out()//  t3{while(!flag)try{this.wait();}catch(InterruptedException e){}//t2  t3System.out.println(Thread.currentThread().getName()+"...消费者........"+this.name);//消费烤鸭1flag = false;notifyAll();}}class Producer implements Runnable{private Resource r;Producer(Resource r){this.r = r;}public void run(){while(true){r.set("烤鸭");}}}class Consumer implements Runnable{private Resource r;Consumer(Resource r){this.r = r;}public void run(){while(true){r.out();}}}class  ProducerConsumerDemo{public static void main(String[] args) {Resource r = new Resource();Producer pro = new Producer(r);Consumer con = new Consumer(r);Thread t0 = new Thread(pro);Thread t1 = new Thread(pro);Thread t2 = new Thread(con);Thread t3 = new Thread(con);t0.start();t1.start();t2.start();t3.start();}}


jdk1.5 新的ReentrantLock(可重入锁)、Condition方法示例


/*jdk1.5以后将同步和锁封装成了对象。 并将操作锁的隐式方式定义到了该对象中,将隐式动作变成了显示动作。Lock接口: 出现替代了同步代码块或者同步函数。将同步的隐式锁操作变成现实锁操作。同时更为灵活。可以一个锁上加上多组监视器。lock():获取锁。unlock():释放锁,通常需要定义finally代码块中。Condition接口:出现替代了Object中的wait notify notifyAll方法。将这些监视器方法单独进行了封装,变成Condition监视器对象。可以任意锁进行组合。await();signal();signalAll();*/import java.util.concurrent.locks.*;class Resource{private String name;private int count = 1;private boolean flag = false;//创建一个锁对象。Lock lock = new ReentrantLock();//通过已有的锁获取该锁上的监视器对象。//Condition con = lock.newCondition();//通过已有的锁获取两组监视器,一组监视生产者,一组监视消费者。Condition producer_con = lock.newCondition();Condition consumer_con = lock.newCondition();public  void set(String name)//  t0 t1{lock.lock();try{while(flag)//try{lock.wait();}catch(InterruptedException e){}//   t1    t0try{producer_con.await();}catch(InterruptedException e){}//   t1    t0this.name = name + count;//烤鸭1  烤鸭2  烤鸭3count++;//2 3 4System.out.println(Thread.currentThread().getName()+"...生产者5.0..."+this.name);//生产烤鸭1 生产烤鸭2 生产烤鸭3flag = true;//notifyAll();//con.signalAll();consumer_con.signal();}finally{lock.unlock();}}public  void out()// t2 t3{lock.lock();try{while(!flag)//try{this.wait();}catch(InterruptedException e){}//t2  t3try{cousumer_con.await();}catch(InterruptedException e){}//t2  t3System.out.println(Thread.currentThread().getName()+"...消费者.5.0......."+this.name);//消费烤鸭1flag = false;//notifyAll();//con.signalAll();producer_con.signal();}finally{lock.unlock();}}}class Producer implements Runnable{private Resource r;Producer(Resource r){this.r = r;}public void run(){while(true){r.set("烤鸭");}}}class Consumer implements Runnable{private Resource r;Consumer(Resource r){this.r = r;}public void run(){while(true){r.out();}}}class  ProducerConsumerDemo2{public static void main(String[] args) {Resource r = new Resource();Producer pro = new Producer(r);Consumer con = new Consumer(r);Thread t0 = new Thread(pro);Thread t1 = new Thread(pro);Thread t2 = new Thread(con);Thread t3 = new Thread(con);t0.start();t1.start();t2.start();t3.start();}}

API示例

class BoundedBuffer {   final Lock lock = new ReentrantLock();   final Condition notFull  = lock.newCondition();    final Condition notEmpty = lock.newCondition();    final Object[] items = new Object[100];   int putptr, takeptr, count;   public void put(Object x) throws InterruptedException {     lock.lock();     try {       while (count == items.length)          notFull.await();       items[putptr] = x;        if (++putptr == items.length) putptr = 0;       ++count;       notEmpty.signal();     } finally {       lock.unlock();     }   }   public Object take() throws InterruptedException {     lock.lock();     try {       while (count == 0)          notEmpty.await();       Object x = items[takeptr];        if (++takeptr == items.length) takeptr = 0;       --count;       notFull.signal();       return x;     } finally {       lock.unlock();     }   }  }


停止线程


*1.定义循环标记

*因为线程运行代码一般都是循环,只要控制了循环即可

*2.使用interrupt(中断)方法

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


注:stop已经过时不再使用


/*停止线程:1,stop方法。(不能用)2,run方法结束。怎么控制线程的任务结束呢?任务中都会有循环结构,只要控制住循环就可以结束任务。控制循环通常就用定义标记来完成。但是如果线程处于了冻结状态,无法读取标记。如何结束呢?可以使用interrupt()方法将线程从冻结状态强制恢复到运行状态中来,让线程具备cpu的执行资格。 当时强制动作会发生了InterruptedException,记得要处理*/class StopThread implements Runnable{private boolean flag = true;public synchronized void run(){while(flag){try{wait();//t0 t1}catch (InterruptedException e){System.out.println(Thread.currentThread().getName()+"....."+e);flag = false;}System.out.println(Thread.currentThread().getName()+"......++++");}}public void setFlag(){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.setDaemon(true);t2.start();int num = 1;for(;;){if(++num==50){//st.setFlag();t1.interrupt();//t2.interrupt();break;}System.out.println("main...."+num);}System.out.println("over");}}


jion()方法、setDeamon方法(设置一个后台线程,随着其他线程消亡而消亡)、yield方法(临时暂停 执行一次任务后自动放弃执行权)


/*join:当A线程执行到了B线程的.join()方法时,A就会等待。等B线程都执行完,A才会执行。join可以用来临时加入线程执行。*/class Demo implements Runnable{public void run(){for(int x=0; x<50; x++){System.out.println(Thread.currentThread().toString()+"....."+x);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();t2.start();//t2.setPriority(Thread.MAX_PRIORITY);//t1.join();//t1线程要申请加入进来,运行。临时加入一个线程运算时可以使用join方法。for(int x=0; x<50; x++){//System.out.println(Thread.currentThread()+"....."+x);}}}




0 0
原创粉丝点击