• 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方法中进行声明,并不能保证调用方法的线程的执行同步/顺序性,也就是线程调用方法的顺序是无序的,虽然在同步块中执行的顺序是同步的,这样就容易出现脏读问题。

  • 相关阅读:
    如何在XSLT中实现勾选的效果
    6个jQuery图表Web应用扩展
    数据仓库(集市)之间共享维度表
    Json.NET
    jquery调用页面的方法
    使用javascript打开模态对话框
    使用ApplicationDeployment 类以编程方面对ClickOnce程序进行更新 【转载】
    XSLT 编译器 (xsltc.exe)
    在xslt中添加链接的方式
    哀悼
  • 原文地址:https://www.cnblogs.com/dream-to-pku/p/6308568.html
Copyright © 2020-2023  润新知