美文网首页Java
Java 多线程 线程间通信-等待唤醒机制

Java 多线程 线程间通信-等待唤醒机制

作者: 一亩三分甜 | 来源:发表于2019-08-19 01:53 被阅读0次

    线程间通讯:其实就是多个线程在操作同一个资源,但是操作的动作不同。

    class Res
    {
        String name;
        String sex;
    }
    class Input implements Runnable
    {
        private Res r;
        private int x = 0;
        Input(Res r)
        {
            this.r = r;
        }
        public void run()
        {
            while (true)
            {
                synchronized (r)
                {
                    if (x==0)
                    {
                        r.name = "mike";
                        r.sex = "man";
                    }
                    else
                    {
                        r.name = "丽丽";
                        r.sex = "女女女女女女";
                    }
                    x = (x+1)%2;
                }
            }
        }
    }
    class Output implements Runnable
    {
        private Res r;
        Output(Res r)
        {
            this.r = r;
        }
        public void run()
        {
            while (true)
            {
                synchronized (r)
                {
                    System.out.println(r.name+"....."+r.sex);
                }
            }
        }
    }
    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();
        }
    }
    //输出正常
    mike.....man
    mike.....man
    mike.....man
    丽丽.....女女女女女女
    丽丽.....女女女女女女
    丽丽.....女女女女女女
    

    wait();notify();notifyAll();都使用在同步中,因为要对持有监视器(锁)的线程操作。所以要使用在同步中,因为只有同步才具有锁。

    为什么这些操作线程的方法要定义object类中呢?
    因为这些方法在操作同步中线程时,都必须要标识他们所操作线程持有的锁,只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒。不可以对不同锁中的线程进行唤醒。
    也就是说,等待和唤醒必须是同一个锁。
    而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中。

    class Res
    {
        String name;
        String sex;
        boolean flag = false;
    }
    class Input implements Runnable
    {
        private Res r;
        private int x = 0;
        Input(Res r)
        {
            this.r = r;
        }
        public void run()
        {
            while (true)
            {
                synchronized (r)
                {
                    if (r.flag)
                        try { r.wait(); }catch (InterruptedException e){}
                    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(Res 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();
                }
            }
        }
    }
    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();
        }
    }
    //输出
    mike.....man
    丽丽.....女女女女女女
    mike.....man
    丽丽.....女女女女女女
    mike.....man
    丽丽.....女女女女女女
    mike.....man
    丽丽.....女女女女女女
    mike.....man
    丽丽.....女女女女女女
    

    优化代码为同步函数形式

    class Res0 {
        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 Input0 implements Runnable {
        private Res0 r;
        private int x = 0;
    
        Input0(Res0 r) {
            this.r = r;
        }
    
        public void run() {
            while (true) {
                if (x == 0) {
                    r.set("mike", "man");
                } else {
                    r.set("丽丽", "女女女女女女");
                }
                x = (x + 1) % 2;
            }
        }
    }
    
    class Output0 implements Runnable {
        private Res0 r;
    
        Output0(Res0 r) {
            this.r = r;
        }
    
        public void run() {
            while (true) {
                r.out();
            }
        }
    }
    
    public class InputOutputDemo0 {
        public static void main(String[] args) {
            Res0 r = new Res0();
            new Thread(new Input0(r)).start();
            new Thread(new Output0(r)).start();
        }
    }
    //输出
    mike.....man
    丽丽.....女女女女女女
    mike.....man
    丽丽.....女女女女女女
    mike.....man
    丽丽.....女女女女女女
    mike.....man
    丽丽.....女女女女女女
    mike.....man
    丽丽.....女女女女女女
    

    多个生产者和消费者情况

    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++;
            System.out.println(Thread.currentThread().getName()+".....生产者"+this.name);
            flag = true;
            this.notifyAll();
        }
        public synchronized void out()
        {
            while(!flag)
                try { this.wait(); }catch (InterruptedException e){}
            System.out.println(Thread.currentThread().getName()+"......消费者"+this.name);
            flag = false;
            this.notifyAll();
        }
    }
    class Producer implements Runnable {
        private Resource res;
    
        Producer(Resource res)
        {
            this.res = res;
        }
        public void run()
        {
            while (true)
    //        for (int i = 0;i<1000;i++)
            res.set("+商品+");
        }
    }
    class Consumer implements Runnable
    {
        private Resource res;
        Consumer(Resource res)
        {
            this.res = res;
        }
        public void  run()
        {
            while (true)
    //        for (int i = 0;i<1000;i++)
            res.out();
        }
    }
    public class ProducerConsumerDemo {
        public static void main(String[] args) {
            Resource res = new Resource();
            Producer p1 = new Producer(res);
            Consumer c1 = new Consumer(res);
            Thread t1 = new Thread(p1);
            Thread t2 = new Thread(p1);
            Thread t3 = new Thread(c1);
            Thread t4 = new Thread(c1);
    
            t1.start();
            t2.start();
            t3.start();
            t4.start();
        }
    }
    为什么要定义while判断标记。
    原因:让被唤醒的线程再一次判断标记。
    为什么定义nofigyAll,因为需要唤醒对方线程。因为只用notify,容易出现只唤醒本方线程的情况,导致程序中的所有线程都等待。
    

    JDK1.5.0中提供了多线程升级解决方案。将同步Synchronized替换成显示Lock操作。将Object中的wait,notify,notifyAll,替换了Condition对象。该对象可以Lock锁进行获取。该示例中,实现了本方只唤醒本方操作。

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    class Resource0
    {
        private String name;
        private int count = 1;
        private boolean flag = false;
        private Lock lock = new ReentrantLock();
        private Condition condition = lock.newCondition();
        public void set(String name)throws InterruptedException
        {
            lock.lock();
            try{
                while(flag)
                    condition.await();
                this.name = name+"--"+count++;
                System.out.println(Thread.currentThread().getName()+".....生产者"+this.name);
                flag = true;
                condition.signal();
            }
            finally {
                lock.unlock();
            }
        }
        public void out() throws InterruptedException
        {
            lock.lock();
            try {
                while(!flag)
                    condition.await();
                System.out.println(Thread.currentThread().getName()+"......消费者"+this.name);
                flag = false;
                condition.signal();
            }
            finally {
                lock.unlock();
            }
        }
    }
    class Producer0 implements Runnable {
        private Resource0 res;
    
        Producer0(Resource0 res)
        {
            this.res = res;
        }
        public void run()
        {
            while (true)
                try{
                    //        for (int i = 0;i<1000;i++)
                    res.set("+商品+");
                }
                catch (InterruptedException e)
                {
    
                }
        }
    }
    class Consumer0 implements Runnable
    {
        private Resource0 res;
        Consumer0(Resource0 res)
        {
            this.res = res;
        }
        public void  run()
        {
            while (true)
                try {
                    //        for (int i = 0;i<1000;i++)
                    res.out();
                }catch (InterruptedException e)
                {
    
                }
    
        }
    }
    public class ProducerConsumerDemo0 {
        public static void main(String[] args) {
            Resource0 res = new Resource0();
            Producer0 p1 = new Producer0(res);
            Consumer0 c1 = new Consumer0(res);
            Thread t1 = new Thread(p1);
            Thread t2 = new Thread(p1);
            Thread t3 = new Thread(c1);
            Thread t4 = new Thread(c1);
    
            t1.start();
            t2.start();
            t3.start();
            t4.start();
        }
    }
    //输出:全部唤醒,程序无法结束
    
    0.gif

    condition.signal()唤醒本方线程,造成相互等待程序无法结束。

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    class Resource0
    {
        private String name;
        private int count = 1;
        private boolean flag = false;
        private Lock lock = new ReentrantLock();
        private Condition condition = lock.newCondition();
        public void set(String name)throws InterruptedException
        {
            lock.lock();
            try{
                while(flag)
                    condition.await();
                this.name = name+"--"+count++;
                System.out.println(Thread.currentThread().getName()+".....生产者"+this.name);
                flag = true;
                condition.signalAll();
            }
            finally {
                lock.unlock();
            }
        }
        public void out() throws InterruptedException
        {
            lock.lock();
            try {
                while(!flag)
                    condition.await();
                System.out.println(Thread.currentThread().getName()+"......消费者"+this.name);
                flag = false;
                condition.signalAll();
            }
            finally {
                lock.unlock();
            }
        }
    }
    class Producer0 implements Runnable {
        private Resource0 res;
    
        Producer0(Resource0 res)
        {
            this.res = res;
        }
        public void run()
        {
            while (true)
                try{
                    //        for (int i = 0;i<1000;i++)
                    res.set("+商品+");
                }
                catch (InterruptedException e)
                {
    
                }
        }
    }
    class Consumer0 implements Runnable
    {
        private Resource0 res;
        Consumer0(Resource0 res)
        {
            this.res = res;
        }
        public void  run()
        {
            while (true)
                try {
                    //        for (int i = 0;i<1000;i++)
                    res.out();
                }catch (InterruptedException e)
                {
    
                }
    
        }
    }
    public class ProducerConsumerDemo0 {
        public static void main(String[] args) {
            Resource0 res = new Resource0();
            Producer0 p1 = new Producer0(res);
            Consumer0 c1 = new Consumer0(res);
            Thread t1 = new Thread(p1);
            Thread t2 = new Thread(p1);
            Thread t3 = new Thread(c1);
            Thread t4 = new Thread(c1);
    
            t1.start();
            t2.start();
            t3.start();
            t4.start();
        }
    }
    //输出正常
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    class Resource0
    {
        private String name;
        private int count = 1;
        private boolean flag = false;
        private Lock lock = new ReentrantLock();
        private Condition condition_pro = lock.newCondition();
        private Condition condition_con = lock.newCondition();
    
    //    private Condition condition = lock.newCondition();
    
        public void set(String name)throws InterruptedException
        {
            lock.lock();
            try{
                while(flag)
                    condition_pro.await();
                this.name = name+"--"+count++;
                System.out.println(Thread.currentThread().getName()+"...生产者"+this.name);
                flag = true;
                condition_con.signal();
            }
            finally {
                lock.unlock();
            }
        }
        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();
            }
            finally {
                lock.unlock();
            }
        }
    }
    class Producer0 implements Runnable {
        private Resource0 res;
    
        Producer0(Resource0 res)
        {
            this.res = res;
        }
        public void run()
        {
            while (true)
                try{
                    //        for (int i = 0;i<1000;i++)
                    res.set("+商品+");
                }
                catch (InterruptedException e)
                {
    
                }
        }
    }
    class Consumer0 implements Runnable
    {
        private Resource0 res;
        Consumer0(Resource0 res)
        {
            this.res = res;
        }
        public void  run()
        {
            while (true)
                try {
                    //        for (int i = 0;i<1000;i++)
                    res.out();
                }catch (InterruptedException e)
                {
    
                }
    
        }
    }
    public class ProducerConsumerDemo0 {
        public static void main(String[] args) {
            Resource0 res = new Resource0();
            Producer0 p1 = new Producer0(res);
            Consumer0 c1 = new Consumer0(res);
            Thread t1 = new Thread(p1);
            Thread t2 = new Thread(p1);
            Thread t3 = new Thread(c1);
            Thread t4 = new Thread(c1);
    
            t1.start();
            t2.start();
            t3.start();
            t4.start();
        }
    }
    //输出正常
    

    停止线程

    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;
        }
    }
    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)
                {
                    st.changeFlag();
                    break;
                }
                System.out.println(Thread.currentThread().getName()+"......"+num);
            }
        }
    }
    //输出正常:num到60,改变标记flag,结束循环,结束打印,结束线程。
    ...
    main......50
    Thread-0...run
    main......51
    Thread-1...run
    main......52
    Thread-0...run
    main......53
    Thread-1...run
    main......54
    Thread-0...run
    main......55
    Thread-1...run
    main......56
    main......57
    main......58
    Thread-0...run
    Thread-0...run
    main......59
    Thread-1...run
    main......60
    Thread-0...run
    Thread-1...run
    

    线程无法中断

    class  StopThread0 implements Runnable
    {
        private Boolean flag = true;
        public synchronized void run()
        {
            while (flag)
            {
                try{
                    wait();
                }catch (InterruptedException e)
                {
                    System.out.println(Thread.currentThread().getName()+"...run"+e.toString());
                }
                System.out.println(Thread.currentThread().getName()+"...run");
            }
        }
        public void changeFlag()
        {
            flag = false;
        }
    }
    public class StopThreadDemo0 {
        public static void main(String[] args) {
            StopThread0 st = new StopThread0();
    
            Thread t1 = new Thread(st);
            Thread t2 = new Thread(st);
    
            t1.start();
            t2.start();
    
            int num = 0;
    
            while (true)
            {
                if (num++ == 60)
                {
                    st.changeFlag();
                    break;
                }
                System.out.println(Thread.currentThread().getName()+"......"+num);
            }
            System.out.println(Thread.currentThread().getName()+"over");
        }
    }
    //输出:程序无法结束
    
    2.gif
    class  StopThread0 implements Runnable
    {
        private Boolean flag = true;
        public synchronized void run()
        {
            while (flag)
            {
                try{
                    wait();
                }catch (InterruptedException e)
                {
                    System.out.println(Thread.currentThread().getName()+"...run"+e.toString());
                }
                System.out.println(Thread.currentThread().getName()+"...run");
            }
        }
        public void changeFlag()
        {
            flag = false;
        }
    }
    public class StopThreadDemo0 {
        public static void main(String[] args) {
            StopThread0 st = new StopThread0();
    
            Thread t1 = new Thread(st);
            Thread t2 = new Thread(st);
    
            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(Thread.currentThread().getName()+"over");
        }
    }
    //输出:程序无法结束
    
    4.gif

    程序结束

    class  StopThread0 implements Runnable
    {
        private Boolean flag = true;
        public synchronized void run()
        {
            while (flag)
            {
                try{
                    wait();
                }catch (InterruptedException e)
                {
                    System.out.println(Thread.currentThread().getName()+"...run"+e.toString());
                    flag = false;
                }
                System.out.println(Thread.currentThread().getName()+"...run");
            }
        }
        public void changeFlag()
        {
            flag = false;
        }
    }
    public class StopThreadDemo0 {
        public static void main(String[] args) {
            StopThread0 st = new StopThread0();
    
            Thread t1 = new Thread(st);
            Thread t2 = new Thread(st);
    
            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(Thread.currentThread().getName()+"over");
        }
    }
    //输出正常
    main......50
    main......51
    main......52
    main......53
    main......54
    main......55
    main......56
    main......57
    main......58
    main......59
    main......60
    mainover
    Thread-0...runjava.lang.InterruptedException
    Thread-0...run
    Thread-1...runjava.lang.InterruptedException
    Thread-1...run
    

    守护线程

    class  StopThread1 implements Runnable
    {
        private Boolean flag = true;
        public void run()
        {
            while (flag)
            {
                System.out.println(Thread.currentThread().getName()+"...run");
            }
        }
        public void changeFlag()
        {
            flag = false;
        }
    }
    public class StopThreadDemo1 {
        public static void main(String[] args) {
            StopThread1 st = new StopThread1();
    
            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(Thread.currentThread().getName()+"over");
        }
    }
    //输出
    Thread-0...run
    main......58
    Thread-1...run
    main......59
    Thread-0...run
    Thread-0...run
    main......60
    Thread-1...run
    Thread-0...run
    Thread-0...run
    Thread-0...run
    Thread-1...run
    Thread-1...run
    Thread-0...run
    Thread-0...run
    Thread-1...run
    Thread-0...run
    mainover
    Thread-1...run
    Thread-0...run
    Thread-1...run
    Thread-0...run
    Thread-1...run
    Thread-0...run
    Thread-1...run
    Thread-0...run
    Thread-1...run
    Thread-0...run
    

    join方法:当A线程执行到了B线程的.join()方法时,A就会等待。等B线程都执行完,A才会执行。join可以用来临时加入线程执行。

    class Demo6 implements Runnable
    {
        public void run()
        {
            for (int x = 0;x<60;x++)
            {
                System.out.println(Thread.currentThread().getName()+"....."+x);
            }
        }
    }
    public class JoinDemo {
        public static void main(String[] args) throws InterruptedException
        {
           Demo6 d = new Demo6();
           Thread t1 = new Thread(d);
           Thread t2 = new Thread(d);
           t1.start();
           t1.join();
           t2.start();
    
           for (int x=0;x<70;x++)
           {
               System.out.println("main......"+x);
           }
           System.out.println("over");
        }
    }
    //输出:t1线程执行完才回到主线程
    ...
    Thread-0.....55
    Thread-0.....56
    Thread-0.....57
    Thread-0.....58
    Thread-0.....59
    Thread-1.....0
    Thread-1.....1
    Thread-1.....2
    ...
    

    优先级

    class Demo7 implements Runnable
    {
        public void run()
        {
            for (int x = 0;x<60;x++)
            {
                System.out.println(Thread.currentThread().toString()+"....."+x);
            }
        }
    }
    public class PriorityYeildDemo {
        public static void main(String[] args) throws InterruptedException
        {
            Demo7 d = new Demo7();
            Thread t1 = new Thread(d);
            Thread t2 = new Thread(d);
            t1.start();
            t1.setPriority(Thread.MAX_PRIORITY);
            t2.start();
    
            for (int x=0;x<70;x++)
            {
                System.out.println("main......"+x);
            }
            System.out.println("over");
        }
    }
    //输出:优先级为10
    Thread[Thread-1,5,main].....0
    Thread[Thread-0,10,main].....0
    Thread[Thread-1,5,main].....1
    Thread[Thread-0,10,main].....1
    Thread[Thread-1,5,main].....2
    Thread[Thread-0,10,main].....2
    ...
    Thread[Thread-1,5,main].....57
    Thread[Thread-0,10,main].....56
    Thread[Thread-1,5,main].....58
    Thread[Thread-0,10,main].....57
    Thread[Thread-1,5,main].....59
    Thread[Thread-0,10,main].....58
    Thread[Thread-0,10,main].....59
    

    yield

    class Demo7 implements Runnable
    {
        public void run()
        {
            for (int x = 0;x<60;x++)
            {
                System.out.println(Thread.currentThread().toString()+"....."+x);
                Thread.yield();
            }
        }
    }
    public class PriorityYeildDemo {
        public static void main(String[] args) throws InterruptedException
        {
            Demo7 d = new Demo7();
            Thread t1 = new Thread(d);
            Thread t2 = new Thread(d);
            t1.start();
            t2.start();
    
            for (int x=0;x<70;x++)
            {
                System.out.println("main......"+x);
            }
            System.out.println("over");
        }
    }
    //输出:中断当前线程,线程交替更频繁
    Thread[Thread-0,5,main].....0
    Thread[Thread-0,5,main].....1
    Thread[Thread-0,5,main].....2
    Thread[Thread-1,5,main].....0
    Thread[Thread-0,5,main].....3
    Thread[Thread-1,5,main].....1
    Thread[Thread-0,5,main].....4
    Thread[Thread-1,5,main].....2
    Thread[Thread-0,5,main].....5
    Thread[Thread-1,5,main].....3
    Thread[Thread-0,5,main].....6
    

    多线程的使用:匿名内部类,继承或实现封装

    public class ThreadTest {
        public static void main(String[] args) {
            new Thread(){
                public void run()
                {
                    for (int x = 0;x <100;x++)
                    {
                        System.out.println(Thread.currentThread().toString()+"..."+x);
                    }
                }
            }.start();
    
            for (int x = 0;x <100;x++)
            {
                System.out.println(Thread.currentThread().toString()+"..."+x);
            }
    
            Runnable r = new Runnable(){
                public void  run()
                {
                    for (int x = 0;x <100;x++)
                    {
                        System.out.println(Thread.currentThread().toString()+"..."+x);
                    }
                }
            };
            new Thread(r).start();
        }
    }
    //封装
    class Demo8 extends Thread
    {
        public void run()
        {
            for (int x = 0;x <100;x++)
            {
                System.out.println(Thread.currentThread().toString()+"..."+x);
            }
        }
    }
    

    相关文章

      网友评论

        本文标题:Java 多线程 线程间通信-等待唤醒机制

        本文链接:https://www.haomeiwen.com/subject/nqmdsctx.html