黑马程序员:Java培训、Android培训、iOS培训、.Net培训

         JAVA线程-synchronized详解

一、synchronized概述

1、线程间实现互斥,必须使用同一个监视器(一个对象)

2、synchronized的作用:为同步代码块或同步方法指定监视器

3、使用同一个监视器的多块代码块或多个方法,在任何时刻,只有获得监视器的线程可访问其中的一块代码块或方法。

 

二、synchronized作用对象

1、synchronized语句块:需要显式指定监视器

1)生成一个对象obj,synchronized(obj){代码块}

2)synchronized(this){代码块}

3)synchronized(className.class){代码块}

2、synchronized方法:使用默认的监视器

     1)实例方法,默认的监视器为:this

     2)类方法,默认的监视器为:className.class(Class对象)

三、看似使用了同一个监视器,实际不是

    1、使用方法体内的对象作为监视器

        public void method(){

            Object obj = new Object();

            synchronized(obj){代码块}

        }

       

        原因:每次调用该法,都会产生新的对象obj,即新的监视器,线程间不会使用同一个监视器

        解决办法:使用类的实例成员,即把“Object obj = new Object();”放到方法体外

2、使用类实例成员作为监视器需要注意两个个问题:

   (1)当这个成员指向的对象发生改变时,监视器就会发生改变。例如:

        String str = new String(“123”);

        public synchronized(str) void method1(){……}  // method1使用监视器”123”

        str = new String(“456”);

        public synchronized(str) void method2(){……}  // method2使用监视器”456”

        原因:使用不同的监视器,method1与method2不能同步。如果通过方法改变str的指向,则会出现令人迷惑的同步问题。

        解决办法:作为监视器的类实例成员使用final声明

   (2)使用类实例成员作为类方法的监视器是错误的:即实例成员不能作为类方法的监视器。

    3、实例方法和类方法

        public synchronized void objMethod(){ ….. }

        public static synchronized void staticMethod(){……}

       

        原因:实例方法使用的监视器是:this;而类方法使用的监视器是:className.class

解决办法:将实例方法改为如下

                  public synchronized(className.class) void objMethod(){ ….. }

 

 

一个问题:子线程循环10次,然后主线程循环20次,如此循环30次

   技术要点:1、轮询条件

             2、使用Object的wait()和notify()

技术要求:1、子线程任务:循环10次

             2、主线程任务:循环20次

             3、子线程任务与主线程任务存在关联(轮流运行),应当放在同一个类(类的封装设计原则之一)

             4、子线程任务与主线程任务需要协作

             5、子线程任务和主线程任务各执行30次

 

可使用阻塞队列设计思想来修改Business的代码:注意判断条件

 

         class Business{

             private boolean isSubSchudule = ture; //使用boolean变量实现线程间协作

             public synchronized void sub(int loop){

                while (!isSubSchudule) {  //这里可使用while替换if,避免假唤醒

                    try{

                        this.wait();

                    }catch(…){

                        …..

                    }

                }

               

                for(int i = 0; i < 10; i++){

                    System.out.println(“sub :” + i + “  loop:” + loop);

                }

                isSubSchudule = false;

                this.notify();

}

            

             public synchronized void main(int loop){

                while (isSubSchudule){ //这里可使用while替换if,避免假唤醒

                    try{

                        this.wait();

                    }catch(…){

                        …..

                    }

                }

                for(int i = 0; i < 20; i++){

                    System.out.println(“main : :” + i + “  loop:” + loop);

                }

                isSubSchudule = ture;

                this.notify();

}

         }

        

         //main()

         Business business = new Business();

         Thread thread = new Thread(new Runnable(){

public void run(){

 for(int i = 0; i < 30; i++){business.sub(i);}}}).start();

        

         for(int i = 0; i < 30; i++){    //将任务加入到主线程种,不用实现Runnable

             business.main(i);