浅谈多线程并发

一句话总结:

            通过wait 、notify、synchronized锁、flag标记位来实现线程的交替执行

核心代码:

            synchronized (s) 
            {
                if (s.flag)
                s.wait();
                //自定义操作
                s.flag = true;
                s.notify();
            }

-------------------------------------------------------对上课内容的总结如下-------------------------------------------------------

代码目的:实现女孩线程和男孩线程交替问问题

一、两个线程仅加锁的情况,会出现一个线程重复抢占资源

package cn.sgy.io.system;

public class WaitNotifyDemo {

    public static void main(String[] args) {

        Student s = new Student();
        s.setName("Tom");
        s.setGender('男');

        new Thread(new Ask(s)).start();
        new Thread(new Change(s)).start();

    }

}

class Change implements Runnable {

    private Student s;

    public Change(Student s) {
        this.s = s;
    }

    public void run() {

        while (true) {
            synchronized (s){if (s.getGender() == '男') {
                s.setName("Amy");
                s.setGender('女');
            } else {
                s.setName("Tom");
                s.setGender('男');
            }

            }
        }

    }
}

    
    
    class Ask implements Runnable {

        private Student s;

        public Ask(Student s) {
            this.s = s;
        }

        @Override
        public void run() {

            while (true) {

               synchronized (s) {
                    
                System.out.println("我是" + s.getName() + ",我是" + s.getGender());
                System.out.println("请教了一个问题~~~");

                }
            }
        }

    }

class Student {

    private String name;
    private char gender;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }
}

二、两个线程加锁内加Thread.sleep,结果无济于事只会让程序变慢(sleep不会打破锁机制)

package cn.sgy.io.system;

public class WaitNotifyDemo {

    public static void main(String[] args) {

        Student s = new Student();
        s.setName("Tom");
        s.setGender('男');

        new Thread(new Ask(s)).start();
        new Thread(new Change(s)).start();

    }

}

class Change implements Runnable {

    private Student s;

    public Change(Student s) {
        this.s = s;
    }

    public void run() {

        while (true) {
            synchronized (s) {
                

            if (s.getGender() == '男') {
                s.setName("Amy");
                s.setGender('女');
            } else {
                s.setName("Tom");
                s.setGender('男');
            }
            
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            }
        }

    }
}

    
    
    class Ask implements Runnable {

        private Student s;

        public Ask(Student s) {
            this.s = s;
        }

        @Override
        public void run() {

            while (true) {

                synchronized (s) {
                    
                System.out.println("我是" + s.getName() + ",我是" + s.getGender());
                System.out.println("请教了一个问题~~~");

                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

    }

class Student {

    private String name;
    private char gender;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }
}

三、在锁内加入等待唤醒机制,结果两个线程都在等待没有任何输出

package cn.sgy.io.system;

public class WaitNotifyDemo {

    public static void main(String[] args) {

        Student s = new Student();
        s.setName("Tom");
        s.setGender('男');

        new Thread(new Ask(s)).start();
        new Thread(new Change(s)).start();

    }

}

class Change implements Runnable {

    private Student s;

    public Change(Student s) {
        this.s = s;
    }

    public void run() {

        while (true) {
            synchronized (s) {
                

               try {
                    s.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }if (s.getGender() == '男') {
                s.setName("Amy");
                s.setGender('女');
            } else {
                s.setName("Tom");
                s.setGender('男');
            }
            
            s.notify();
            }

            }
        }

    }


    
    
    class Ask implements Runnable {

        private Student s;

        public Ask(Student s) {
            this.s = s;
        }

        @Override
        public void run() {

            while (true) {

                synchronized (s) {
                    try {
                        s.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                System.out.println("我是" + s.getName() + ",我是" + s.getGender());
                System.out.println("请教了一个问题~~~");

                }
                s.notify();
                }
            }
        }

    

class Student {

    private String name;
    private char gender;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }
}

四、加入标记位(flag=true -> Ask线程     flag=false -> Change线程)

 

package cn.sgy.io.system;

public class WaitNotifyDemo {

    public static void main(String[] args) {

        Student s = new Student();
        s.setName("Tom");
        s.setGender('男');

        new Thread(new Ask(s)).start();
        new Thread(new Change(s)).start();

    }

}

class Change implements Runnable {

    private Student s;

    public Change(Student s) {
        this.s = s;
    }

    public void run() {

        while (true) {
            synchronized (s) {
                
                if(s.flag == true)

                try {
                    s.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            if (s.getGender() == '男') {
                s.setName("Amy");
                s.setGender('女');
            } else {
                s.setName("Tom");
                s.setGender('男');
            }
            s.flag=true;
            
            s.notify();
            }

            }
        }

    }


    
    
    class Ask implements Runnable {

        private Student s;

        public Ask(Student s) {
            this.s = s;
        }

        @Override
        public void run() {

            while (true) {

                synchronized (s) {
                    
                    if(s.flag == false)try {
                        s.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                System.out.println("我是" + s.getName() + ",我是" + s.getGender());
                System.out.println("请教了一个问题~~~");

                s.flag = false;
                
                s.notify();
                }
                
                }
            }
        }

    

class Student {

    private String name;
    private char gender;

    public boolean flag = true;
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }
}

五、每个线程类对应了两个线程后出现问题

package cn.tedu.thread;

public class WaitNotifyAllDemo {

    public static void main(String[] args) {

        Student s = new Student();
        s.setName("Tom");
        s.setGender('男');

        new Thread(new Ask2(s)).start();
        new Thread(new Ask2(s)).start();
        new Thread(new Change2(s)).start();
        new Thread(new Change2(s)).start();
    }

}

class Change2 implements Runnable {

    private Student s;

    public Change2(Student s) {
        this.s = s;
    }

    @Override
    public void run() {

        while (true) {

            synchronized (s) {

                while (s.flag)
                    try {
                        s.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                if (s.getGender() == '男') {
                    s.setName("Amy");
                    s.setGender('女');
                } else {
                    s.setName("Tom");
                    s.setGender('男');
                }

                s.flag = true;

                // 唤醒在等待的线程
 s.notify();

            }

        }

    }

}

class Ask2 implements Runnable {

    private Student s;

    public Ask2(Student s) {
        this.s = s;
    }

    @Override
    public void run() {

        while (true) {
            synchronized (s) {

                while (!s.flag)
                    try {
                        s.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                System.out.println("我是" + s.getName() + ",我是" + s.getGender());
                System.out.println("请教了一个问题~~~");

                s.flag = false;

                s.notify();
            }
        }

    }

}

六、出现问题的原因

知识基础:线程在等待期间是在这个锁所对应的线程池(队列)中等待

一句话总结:A执行完,应该释放C时却把排在C前面的A释放,导致C无法执行

解释:A1为 Ask线程   A2为Ask2线程   两者为同一操作  

         C1为Change线程 C2位Change2线程   两者为同一操作

因为队列只能先进先出,所以释放的时候都是释放最先进入的元素,所以当遇到且仅遇到以下两种情况时会出现全部进入线程池的情况

        

当C程序执行结束,而C线程再一次抢到资源的时候,因为交替执行需要的A线程,所以把抢到资源的C1和C2都放入了线程池中,这时才轮到A2线程来执行A程序



七、使用 s.notifyAll()解决问题

notifyAll用于释放线程池中的所有等待的线程,因为使得代码整洁才使用这种低效率的方法

package cn.tedu.thread;

public class WaitNotifyAllDemo {

    public static void main(String[] args) {

        Student s = new Student();
        s.setName("Tom");
        s.setGender('男');

        new Thread(new Ask2(s)).start();
        new Thread(new Ask2(s)).start();
        new Thread(new Change2(s)).start();
        new Thread(new Change2(s)).start();
    }

}

class Change2 implements Runnable {

    private Student s;

    public Change2(Student s) {
        this.s = s;
    }

    @Override
    public void run() {

        while (true) {

            synchronized (s) {

                while (s.flag)
                    try {
                        s.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                if (s.getGender() == '男') {
                    s.setName("Amy");
                    s.setGender('女');
                } else {
                    s.setName("Tom");
                    s.setGender('男');
                }

                s.flag = true;

                // 唤醒在等待的线程
 s.notifyAll();

            }

        }

    }

}

class Ask2 implements Runnable {

    private Student s;

    public Ask2(Student s) {
        this.s = s;
    }

    @Override
    public void run() {

        while (true) {
            synchronized (s) {

                while (!s.flag)
                    try {
                        s.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                System.out.println("我是" + s.getName() + ",我是" + s.getGender());
                System.out.println("请教了一个问题~~~");

                s.flag = false;

                s.notifyAll();
            }
        }

    }

}

-------------------------------------------------------谢谢观看,如有问题还请指正-------------------------------------------------------

原文地址:https://www.cnblogs.com/songyao2018/p/8407843.html