synchronized將任意對象作為對象監視器


多個線程調用同一個對象中的不同名稱的synchronized同步方法或synchronized(this)同步代碼塊時,調用的效果就是按順序執行,也就是同步的,阻塞的。
這說明synchronized同步方法或synchronized(this)同步代碼塊分別有兩種作用
(1)synchronized同步方法
1)對其他synchronized同步方法或synchronized(this)同步代碼塊調用呈阻塞狀態
2)同一時間只有一個線程可以執行synchronized同步方法中的代碼
(2)synchronized(this)同步代碼塊
1)對其他synchronized同步方法或synchronized(this)同步代碼塊調用呈阻塞狀態
2)同一時間只有一個線程可以執行synchronized(this)同步代碼塊中的代碼
Java還支持對“任意對象”作為“對象監視器”來實現同步的功能。這個“任意對象”大多數是實例變量及方法的參數,使用synchronized(非this對象)
synchronized(非this對象)格式的作用只有1中:synchronized(非this對象x)同步代碼塊
1)在多個線程持有“對象監視器”為同一個對象的前提下,同一時間只有一個線程可以執行synchronized(非this對象x)同步代碼塊中的代碼
2)當持有“對象監視器”為同一個對象的前提下,同一時間只有一個線程可以執行synchronized(非this對象x)同步代碼塊中的代碼。
package synBlockString;

/**
 * Created by Administrator on 2017/1/19 0019.
 */
public class Service {
    private String usernameParam;
    private String passwordParam;
    private String anyString = new String(); public void setUsernamePassword(String username,String password){
        try{
            synchronized (anyString){
                System.out.println("線程名稱為:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"進入同步");
                usernameParam = username;
                Thread.sleep(2000);
                passwordParam = password;
                System.out.println("線程名稱為:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"離開同步");
            }
        }catch(InterruptedException e){
            e.printStackTrace();
        }
    }
}
package synBlockString;

/**
 * Created by Administrator on 2017/1/19 0019.
 */
public class ThreadA extends Thread {
    private Service service;
    public ThreadA(Service service){
        super();
        this.service = service;
    }

    public void run(){
        service.setUsernamePassword("a","aa");
    }
}
package synBlockString;

/**
 * Created by Administrator on 2017/1/19 0019.
 */
public class ThreadB extends Thread {
    private Service service;
    public ThreadB(Service service){
        super();
        this.service = service;
    }
    public void run(){
        service.setUsernamePassword("b","bb");
    }

}
package synBlockString;



/**
 * Created by Administrator on 2017/1/19 0019.
 */
public class Run {
    public static void main(String [] args){
        Service service = new Service();
        ThreadA threadA = new ThreadA(service);
        threadA.setName("A");
        threadA.start();
        ThreadB threadB = new ThreadB(service);
        threadB.setName("B");
        threadB.start();
        threadB.start();

    }
}
線程名稱為:A在1484823811547進入同步
線程名稱為:A在1484823813559離開同步
線程名稱為:B在1484823813559進入同步
線程名稱為:B在1484823815573離開同步

如果修改service.java為

package synBlockString;

/**
 * Created by Administrator on 2017/1/19 0019.
 */
public class Service {
    private String usernameParam;
    private String passwordParam;

    public void setUsernamePassword(String username,String password){
        try{
            String anyString = new String(); synchronized (anyString){
                System.out.println("線程名稱為:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"進入同步");
                usernameParam = username;
                Thread.sleep(2000);
                passwordParam = password;
                System.out.println("線程名稱為:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"離開同步");
            }
        }catch(InterruptedException e){
            e.printStackTrace();
        }
    }
}
線程名稱為:A在1484823870625進入同步
線程名稱為:B在1484823870625進入同步
線程名稱為:B在1484823872638離開同步
線程名稱為:A在1484823872638離開同步

所以,使用synchronized(非this對象)同步代碼塊格式進行同步操作時,對象監視器必須是同一個對象,如果不是同一個對象監視器,運行的結果就是異步調用了,就會交叉運行。

再看下一個示例:

package synBlockString2;


/**
 * Created by Administrator on 2017/1/19 0019.
 */
public class Service  {
    private String anyThing = new String();
    public void a(){
        try {
            synchronized (anyThing){
                System.out.println("a begin");
                Thread.sleep(2000);
                System.out.println("a end");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    synchronized  public void b(){
        System.out.println(" b begin");
        System.out.println(" b end");
    }
}
package synBlockString2;

/**
 * Created by Administrator on 2017/1/19 0019.
 */
public class ThreadA extends Thread {
    private Service service;
    public ThreadA(Service service){
        super();
        this.service = service;
    }
    public  void run(){
        service.a();
    }
}
package synBlockString2;

/**
 * Created by Administrator on 2017/1/19 0019.
 */
public class ThreadB extends Thread {
    private Service service;
    public ThreadB(Service service){
        super();
        this.service = service ;
    }
    public void run(){
        service.b();
    }
}
package synBlockString2;

/**
 * Created by Administrator on 2017/1/19 0019.
 */
public class Run {
    public static void main(String [] args){
        Service service = new Service();
        ThreadA threadA = new ThreadA(service);
        threadA.setName("A");
        threadA.start();
        ThreadB threadB = new ThreadB(service);
        threadB.setName("B");
        threadB.start();
    }
}
運行結果:
a begin
 b begin
 b end
a end

由於對象監視器不同,所以運行結果就是異步的

同步代碼塊放在非同步synchronized方法中進行聲明,並不能保證調用方法的線程的執行同步/順序性,也就是線程調用方法的順序是無序的,雖然在同步塊中執行的順序是同步的,這樣就容易出現臟讀問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM