5.1.5 线程间通信
wait:
notify();
notifyAll();
都使用在同步中,因为要对持有监视器(锁)的线程操作。
所以要使用在同步中,因为只有同步才具有锁。
为什么这些操作线程的方法要定义Object类中呢?
因为这些方法在操作同步中线程时,都必须要标识它们所操作线程只有的锁,
只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒。
不可以对不同锁中的线程进行唤醒。
也就是说,等待和唤醒必须是同一个锁。
而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中。
练习一:线程间通信
- class Res
- {
- String name;
- String sex;
- boolean flag = false;
- }
- class Input implements Runnable
- {
- private Res r ;
- Input(Resr)
- {
- this.r= r;
- }
- public void run()
- {
- int x = 0;
- while(true)
- {
- synchronized(r)
- {
- if(r.flag)
- try{r.wait();}catch(Exceptione){}
- if(x==0)
- {
- r.name="mike";
- r.sex="man";
- }
- else
- {
- r.name="丽丽";
- r.sex= "女女女女女";
- }
- x = (x+1)%2;
- r.flag = true;
- r.notify();
- }
- }
- }
- }
- class Output implements Runnable
- {
- private Res r ;
- Output(Resr)
- {
- this.r= r;
- }
- public void run()
- {
- while(true)
- {
- synchronized(r)
- {
- if(!r.flag)
- try{r.wait();}catch(Exceptione){}
- System.out.println(r.name+"...."+r.sex);
- r.flag= false;
- r.notify();
- }
- }
- }
- }
- 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();
- }
- }
练习二:练习一的优化后
- 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(Exceptione){}//this.wait()中说明这里的锁是this
- this.name= name;
- this.sex= sex;
- flag= true;
- this.notify();
- }
- public synchronized void out()
- {
- if(!flag)
- try{this.wait();}catch(Exceptione){} //this.wait()中说明这里的锁是this
- System.out.println(name+"........"+sex);
- flag= false;
- this.notify();
- }
- }
- class Input implements Runnable
- {
- private Res r ;
- Input(Resr)
- {
- this.r= r;
- }
- public void run()
- {
- intx = 0;
- while(true)
- {
- if(x==0)
- r.set("mike","man");
- else
- r.set("丽丽","女女女女女");
- x= (x+1)%2;
- }
- }
- }
- class Output implements Runnable
- {
- private Res r ;
- Output(Resr)
- {
- this.r= r;
- }
- public void run()
- {
- while(true)
- {
- r.out();
- }
- }
- }
- class InputOutputDemo2
- {
- public static void main(String[] args)
- {
- Resr = new Res();
- newThread(new Input(r)).start();
- newThread(new Output(r)).start();
- //上面两句是下面六句话的简化写法
- /*
- Inputin = new Input(r);
- Outputout = new Output(r);
- Threadt1 = new Thread(in);
- Threadt2 = new Thread(out);
- t1.start();
- t2.start();
- */
- }
- }
练习二:多个生产者消费者
- class ProducerConsumerDemo
- {
- public static void main(String[] args)
- {
- Resourcer = 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();
- }
- }
- /*
- 对于多个生产者和消费者。
- 为什么要定义while判断标记。
- 原因:让被唤醒的线程再一次判断标记。
- 为什么定义notifyAll,
- 因为需要唤醒对方线程。
- 因为只用notify,容易出现只唤醒本方线程的情况。导致程序中的所有线程都等待。
- */
- class Resource
- {
- private String name;
- private int count = 1;
- private boolean flag = false;
- // t1 t2
- public synchronized void set(String name)
- {
- while(flag)
- try{this.wait();}catch(Exceptione){}//t1(放弃资格) t2(获取资格)
- this.name= name+"--"+count++;
- System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
- flag= true;
- this.notifyAll();
- }
- // t3 t4
- public synchronized void out()
- {
- while(!flag)
- try{wait();}catch(Exceptione){}//t3(放弃资格) t4(放弃资格)
- System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);
- flag= false;
- this.notifyAll();
- }
- }
- class Producer implements Runnable
- {
- private Resource res;
- Producer(Resourceres)
- {
- this.res= res;
- }
- publicvoid run()
- {
- while(true)
- {
- res.set("+商品+");
- }
- }
- }
- class Consumer implements Runnable
- {
- private Resource res;
- Consumer(Resourceres)
- {
- this.res= res;
- }
- public void run()
- {
- while(true)
- {
- res.out();
- }
- }
- }
5.1.6 JDK1.5 中提供了多线程升级解决方案。Lock
将同步Synchronized替换成现实Lock操作。
将Object中的wait,notify notifyAll,替换了Condition对象。
该对象可以Lock锁进行获取。
该示例中,实现了本方只唤醒对方操作。
Lock:替代了Synchronized
lock
unlock
newCondition()
Condition:替代了Object wait notify notifyAll
await();
signal();
signalAll();
练习四:用JDK1.5 新特性 Lock来练习多个生产者和消费者
- 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;
- // t1 t2
- private Lock lock = new ReentrantLock();
- private Condition condition_pro = lock.newCondition();
- private Condition condition_con = lock.newCondition();
- public void set(String name)throwsInterruptedException
- {
- 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();//唤醒condition_con
- }
- finally
- {
- lock.unlock();//释放锁的动作一定要执行。
- }
- }
- // t3 t4
- 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();//唤醒condition_pro
- }
- finally
- {
- lock.unlock();
- }
- }
- }
- class Producer implements Runnable
- {
- private Resource res;
- Producer(Resourceres)
- {
- this.res= res;
- }
- public void run()
- {
- while(true)
- {
- try
- {
- res.set("+商品+");
- }
- catch(InterruptedException e)
- {
- }
- }
- }
- }
- class Consumer implements Runnable
- {
- privateResource res;
- Consumer(Resourceres)
- {
- this.res= res;
- }
- public void run()
- {
- while(true)
- {
- try
- {
- res.out();
- }
- catch(InterruptedException e)
- {
- }
- }
- }
- }
5.1.7停止线程
定义循环结束标记
因为线程运行代码一般都是循环,只要控制了循环即可。
使用interrupt(中断)方法。
该方法是结束线程的冻结状态,使线程回到运行状态中来。
注:stop方法已经过时不再使用。
stop方法已经过时。
如何停止线程?
只有一种,run方法结束。
开启多线程运行,运行代码通常是循环结构。
只要控制住循环,就可以让run方法结束,也就是线程结束。
特殊情况:
当线程处于了冻结状态。
就不会读取到标记。那么线程就不会结束。
当没有指定的方式让冻结的线程恢复到运行状态是,这时需要对冻结进行清除。
强制让线程恢复到运行状态中来。这样就可以操作标记让线程结束。
Thread类提供该方法 interrupt();
练习五:如何停止线程
- class StopThread implements Runnable
- {
- private boolean flag =true;
- public void run()
- {
- while(flag)
- {
- 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");
- }
- }
练习六:用匿名内部类创建两种线程
- class ThreadTest
- {
- public static void main(String[] args)
- {
- new Thread()
- {
- public void run()
- {
- for(intx=0; x<100; x++)
- {
- System.out.println(Thread.currentThread().getName()+"....."+x);
- }
- }
- }.start();
- for(intx=0; x<100; x++)
- {
- System.out.println(Thread.currentThread().getName()+"....."+x);
- }
- Runnable r = new Runnable()
- {
- public void run()
- {
- for(intx=0; x<100; x++)
- {
- System.out.println(Thread.currentThread().getName()+"....."+x);
- }
- }
- };
- new Thread(r).start();
- }
- }
5.1.8 Thread类中一些常用的方法
setDaemon(boolean on)
将该线程标记为守护线程或用户线程。
join()
等待该线程终止。
yield()
暂停当前正在执行的线程对象,并执行其他线程。
setPriority(int newPriority)
更改线程的优先级。
MAX_PRIORITY
线程可以具有的最高优先级。
MIN_PRIORITY
线程可以具有的最低优先级。
NORM_PRIORITY
分配给线程的默认优先级