zoukankan      html  css  js  c++  java
  • 多线程03-线程互斥

    1.错误的代码

    package org.lkl.thead.sync;
    
    public class ThreadSynchronized {
    
        class Outputter{
            public void output(String name){
                for(int i = 0 ;i<name.length();i++){
                    System.out.print(name.charAt(i));
                }
            }
            
        }
    
        public static void main(String[] args) {
            new Outputter().output("zhangsan") ; //这里是错误的
        }
    }
    Outputter是ThreadSynchronized 类的内部类  如果在main 这个static的方法中实例化Outputter是不正确的  
    原因分析:内部类实例化以后可以通过内部类去访问外部类中的属性和方法 但是要注意的是static的方法是不需要ThreadSynchronized实例化就可以直接调用的 此时如果在main方法中能实例化Outputter的话 那么在
    main方法中就可以调用ThreadSynchronized类中的其他属性和方法 但此时这些属性和方法可能还没有别初始化 因此不能进行访问.


    2.问题的引入

    看下面的代码
    package org.lkl.thead.sync;
    
    public class ThreadSynchronized {
    
    
        public static void main(String[] args) {
            /**
             * 调用init方法 两个线程同时打印张三和李四 
             */
            new ThreadSynchronized().init() ;
        }
        
        
        
        private void init(){
            
            final Outputter out = new Outputter();
            //通过一个线程打印张三的名字
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while(true){
                        try {
                            Thread.currentThread().sleep(50) ;
                            out.output("zhangsan") ;
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start() ;
            
            //通过一个线程打印李四的名字
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while(true){
                        try {
                            Thread.currentThread().sleep(50) ;
                            out.output("lisi") ;
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start() ;
            
        }
        
        
    
        class Outputter{
            public void output(String name){
                for(int i = 0 ;i<name.length();i++){
                    System.out.print(name.charAt(i));
                }
                System.out.println();
            }
            
        }
    }
    通过两个线程来打印张三和李四的名字  由于他们都是调用同一个Outputter对象的output方法来打印 那么就可能导致打印zhangsan或者lisi字符的时候出现偏差 例如 打印zhangsan的时候只打印了zhang 然后另外一个线程就
    调用了for循环打印了lisi的信息 那么导致zhangsan的名字没有打全

    3.使用synchronized关键字来解决问题

    通过以上可以发现 打印name的这个操作应该是一个整体 在一个人的名字没有全部打印出来以前 是不能让其他的线程来调用for循环的方法 使用synchronized关键字给for循环这段代码加上一把锁,例如
        class Outputter{
            public void output(String name){
                synchronized(this){
                    for(int i = 0 ;i<name.length();i++){
                        System.out.print(name.charAt(i));
                    }
                    System.out.println();
                }
            }
            
        }

     注意一个问题  synchronized中的this 表示的是同步这段代码的锁 那么this表示什么呢?表示的是调用这个方法的对象 即前面定义的out对象  

       synchronized中的锁可以是任意的一个对象 只要是一个对象都可以成为同步块的锁 但不是所有的对象都能锁住这个代码块 ,例如 如果把this替换成name 的话 那么就无法锁住for循环的代码 

    因为两个线程中的name都是不一样的 一个是zhangsan  一个是lisi ,线程1调用for循环的时候 看的是zhangsan这把锁 但是线程2看的是lisi这把锁 很显然两把锁不一致 不能锁住for循环的代码

    4.进一步拓展
        
    
        class Outputter{
            public void output(String name){
                synchronized(this){
                    for(int i = 0 ;i<name.length();i++){
                        System.out.print(name.charAt(i));
                    }
                    System.out.println();
                }
            }
            
            
            public synchronized  void output2(String name){
                    for(int i = 0 ;i<name.length();i++){
                        System.out.print(name.charAt(i));
                    }
                    System.out.println();
            }
        }

        增加一个output2方法  此时代码能锁住for循环的输出吗?  

    由于我们使用的锁是this 即out对象  那么output方法和output2方法都是out中的方法  那显然是能进行代码的同步的

     增加一个静态的output3方法

    static class Outputter{
            public void output(String name){
                synchronized(this){
                    for(int i = 0 ;i<name.length();i++){
                        System.out.print(name.charAt(i));
                    }
                    System.out.println();
                }
            }
            
            
            public synchronized  void output2(String name){
                    for(int i = 0 ;i<name.length();i++){
                        System.out.print(name.charAt(i));
                    }
                    System.out.println();
            }
            
            public static  synchronized  void output3(String name){
                for(int i = 0 ;i<name.length();i++){
                    System.out.print(name.charAt(i));
                }
                System.out.println();
        }

     此时类变成了static的  那么此时能锁住代码吗?

             由于static方法是在类对象还没有产生的时候就可以调用的 那么this很显然是不能锁住代码的  需要使用一个所有方法公共的一个对象  即Outputter.class 在允许的时候会生成一个类的字节码

    不管是static还是非static的方法都是在这个类中的 能达到锁住代码的效果 

             正确代码如下: 

        static class Outputter{
            public void output(String name){
                synchronized(Outputter.class){
                    for(int i = 0 ;i<name.length();i++){
                        System.out.print(name.charAt(i));
                    }
                    System.out.println();
                }
            }
            
            
            public synchronized  void output2(String name){
                    for(int i = 0 ;i<name.length();i++){
                        System.out.print(name.charAt(i));
                    }
                    System.out.println();
            }
            
            public static  synchronized  void output3(String name){
                for(int i = 0 ;i<name.length();i++){
                    System.out.print(name.charAt(i));
                }
                System.out.println();
        }
            
        }
  • 相关阅读:
    ubuntu 进入临时客户会话页面 转入用户自己页面
    python hmac 加密
    docker 学习
    python try except 捕捉错误得到错误的时候的值
    python2 python3 m2crypto 安装(rsa 私钥文件加密)
    python3 requests 模块 json参数和data参数区别
    爬虫-鸡哥给大家的福利
    常用模块2
    python入门到放弃之 面向对象vs面向过程
    python放弃之 模块和包
  • 原文地址:https://www.cnblogs.com/liaokailin/p/3770951.html
Copyright © 2011-2022 走看看