线程之间同步互斥的通信问题之 同步

线程之间同步互斥的通信问题:
java用synchronized关键字做为多线程并发环境的执行有序性的保证手段之一。当一段代码会修改共享变量,这一段代码成为互斥区或临界区,为了保证共享变量的正确性,synchronized标示了临界区。
一个线程执行临界区代码过程如下:
1 获得同步锁
2 清空工作内存
3 从主存拷贝变量副本到工作内存
4 对这些变量计算
5 将变量从工作内存写回到主存
6 释放锁
可见,synchronized既保证了多线程的并发有序性,又保证了多线程的内存可见性。
volatile:volatile只能保证多线程的内存可见性,不能保证多线程的执行有序性。而最彻底的同步要保证有序性和可见性,例如synchronized。任何被volatile修饰的变量,都不拷贝副本到工作内存,任何修改都及时写在主存。因此对于Valatile修饰的变量的修改,所有线程马上就能看到,但是volatile不能保证对变量的修改是有序的。
volatile适合这种场景:一个变量被多个线程共享,线程直接给这个变量赋值。这是一种很简单的同步场景,这时候使用volatile的开销将会非常小。
内部类不可以在其外部类的main方法中直接new,因为内部类的实例化必须在外部类的实例化之后。
当出现两个线程同步进行的时候,会出现小概率事件,
在这里插入图片描述
那么我们就可以使用Synchronized修饰要被同步运行的方法。

package martina.TraditionalThread;

public class TraditionalThreadSynchronized {
    public static void main(String[] args){
        new TraditionalThreadSynchronized().init();
    }
    final static OutPuter outPuter=new OutPuter();
    public  void init(){
        //两个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(true) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        System.out.println("Error:" + e.toString());
                    }
                    outPuter.output("YOUYOUYOUYOU");
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                while(true) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        System.out.println("Error:" + e.toString());
                    }
                    outPuter.output3("MEME");
                }
            }
        }).start();
    }
   static class OutPuter{
        public void output(String name){
            //使用synchronized关键字实现同步
            //由于两个线程都用到了outPuter对象,所以我们synchronized的参数要用outPuter对象
            //如果是每一个线程都单独的创建了一个新的OutPuter对象,那么我们就要将下面的形参改为this
            //如果是想要实现和一个static方法实现同步,则将下面的形参改为OutPuter.class(二进制字节码)
            synchronized(outPuter) {
                for (int i = 0; i < name.length(); i++) {
                    System.out.print("!:" + name.charAt(i));
                }
                System.out.println();
            }
            /*synchronized(this) {
                for (int i = 0; i < name.length(); i++) {
                    System.out.print("!:" + name.charAt(i));
                }
                System.out.println();
            }*/
             /*//要用到OutPuter.class
             synchronized(OutPuter.class) {
                for (int i = 0; i < name.length(); i++) {
                    System.out.print("!:" + name.charAt(i));
                }
                System.out.println();
            }*/
        }

        /**
         * 最简单的办法就是用Synchronized关键字修饰给整个函数
         * 那么将第二个线程使用output2的时候,依然可以和output的线程实现同步
         * @param name
         */
        public synchronized void output2(String name){
                for (int i = 0; i < name.length(); i++) {
                    System.out.print("!:" + name.charAt(i));
                }
                System.out.println();
        }

       /**
        * 这时候output函数中的synchronized的形参要用OutPuter.class,
        * 因为static方法运行的时候是有一个对象与之关联,类的二进制字节码(OutPuter.class)在内存中也是一个对象
        * 所以只有形参改为字节码的时候才能和static修饰的同步方法实现同步
        * @param name
        */
        public static synchronized void output3(String name){
            for (int i = 0; i < name.length(); i++) {
                System.out.print("!:" + name.charAt(i));
            }
            System.out.println();
        }
    };
}

在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/mulinsen77/article/details/84338995
今日推荐