14多线程
线程间通讯:
多个线程在处理同一资源,但是任务却不同.
//资源 class Resource { String name; String sex; } //输入 class Input implements Runnable { Resource r; Input(Resource r) { this.r = r; } public void run() { int x=0; while(true) { synchronized(r) { if(x==0) { r.name="mike"; r.sex="nan"; } else { r.name="丽丽"; r.sex="女女女女"; } x=(x+1)%2; } } } } //输出 class Output implements Runnable { Resource r; Output(Resource r) { this.r = r; } public void run() { while(true) { synchronized(r) { System.out.println(r.name+"..."+r.sex); } } } } class Demo { 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(); } }
等待/唤醒机制:
涉及的方法:
1.wait():让线程处于冻结状态.被wait的线程会被存储到线程池中.
2.notify():唤醒线程池中的一个线程(任意).
3.notifyAll():唤醒线程池中的所有线程.
这些方法都必须定义在同步中.
因为这些方法是用于操作线程状态的方法.
必须要明确到底操作的是哪个锁上的线程.
为什么操作线程的方法wait,notify,notifyAll定义在了Object类中.
因为这些方法是监视器的方法,监视器其实就是锁.
锁可以是任意的对象,任意的对象调用的方法一定定义在Object类中.
//资源 class Resource { 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){} this.name=name; this.sex=sex; flag = true; this.notify(); } public synchronized void out() { if(!flag) try{ this.wait(); } catch(InterruptedException e){} System.out.println(name+"..."+sex); flag=false; this.notify(); } } //输入 class Input implements Runnable { Resource r; Input(Resource r) { this.r = r; } public void run() { int x=0; while(true) { if(x==0) { r.set("mike","man"); } else { r.set("lili","女"); } x=(x+1)%2; } } } //输出 class Output implements Runnable { Resource r; Output(Resource r) { this.r = r; } public void run() { while(true) { r.out(); } } } class Demo { 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(); } }
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){} this.name=name + count; count++; System.out.println(Thread.currentThread().getName()+"..生产者.."+this.name); flag=true; notifyAll(); } public synchronized void out() { while(!flag) try{this.wait();}catch(InterruptedException e){} System.out.println(Thread.currentThread().getName()+"..消费者.."+this.name); flag=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 Demo { 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(); } }
if判断标记,只有一次,回导致不该运行的线程运行了,出现了数据错误的情况.
while判断标记,解决了线程获取执行权后,是否要运行.
notify只能唤醒一个线程,如果本方唤醒了本方,没有意义.而且while判断标记,加notify会导致死锁.
notifyAll解决了,本方线程一定会唤醒对方线程的问题.
同步代码块,对于锁的操作是隐式的.
若code...中throw Exception();锁将不能释放.
故应将lock.unlock()放在finally中.一定要释放.
lock l = ...;
l.lock();
try{
}
finally{
l.unlock();
}
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) { lock.lock(); try { while(flag) try{producer_con.await();}catch(InterruptedException e){} this.name=name + count; count++; System.out.println(Thread.currentThread().getName()+"..生产者.."+this.name); flag=true; //notifyAll(); //con.signalAll(); consumer_con.signal(); } finally { lock.unlock(); } } public void out() { lock.lock(); try { while(!flag) try{consumer_con.await();}catch(InterruptedException e){} System.out.println(Thread.currentThread().getName()+"..消费者.."+this.name); flag=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 Demo { 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(); } }
Lock接口:出现替代了同步代码块或者同步函数.
将同步的隐式锁操作变成了显示锁操作.
同时更为灵活,可以一个锁上加上多组监视器.
lock():获取锁.unlock():释放锁,通常需要定义在finally代码块中.
Condition接口:出现替代了Object中的wait notify notifyAll方法,
将这些监视器方法单独进行了封装,变成了Condition监视器对象,
可以任意锁进行组合.
await();
signal();
signalAll();
wait和sleep的区别:
1.wait可以指定时间,也可以不指定.
而sleep必须指定时间.
2.在同步中时,对于cpu的执行权和锁的处理不同.
wait:释放执行权,释放锁.
sleep:释放执行权,不释放锁.
停止线程:
1.stop方法.
2.run方法结束.
怎么控制线程的任务结束呢?
任务中都会有循环结构,只要控制住循环就可以结束任务.
控制循环通常就用定义标记来完成.
但是如果线程处于了冻结状态,无法读取标记,该如何结束呢?
可以使用interrupt()方法将线程从冻结状态强制恢复到运行状态中来,让线程具备
cpu的执行资格.
但是强制动作会发生InterruptedException,记得要处理.