多线程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();

    }

        

    }

 

 

你可能感兴趣的:(多线程)