多线程之synchronized同步语句块(6)

1.内置类和静态内置类

关键字synchronized的知识点还涉及内置类的使用。先来看一下简单的内置类测试。

package test;

/**
 * @Author LiBinquan
 */
public class PublicClass {
    private String userName;
    private String passWord;
    class PrivateClass {
        private String age;
        private String address;

        public String getAge() {
            return age;
        }

        public void setAge(String age) {
            this.age = age;
        }

        public String getAddress() {
            return address;
        }

        public void setAddress(String address) {
            this.address = address;
        }
        public void printPublicProperty(){
            System.out.println(userName + "  "+passWord);
        }
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }
}

运行类:

package test;

/**
 * @Author LiBinquan
 */
public class Run {
    public static void main(String[] args) throws InterruptedException {
        PublicClass publicClass = new PublicClass();
        publicClass.setUserName("AA");
        publicClass.setPassWord("aaa");
        System.out.println(publicClass.getUserName() + "  "+publicClass.getPassWord());
        PublicClass.PrivateClass privateClass = publicClass.new PrivateClass();
        privateClass.setAge("13");
        privateClass.setAddress("addressValue");
        System.out.println(privateClass.getAge()+" "+privateClass.getAddress());
    }
}

输出:
在这里插入图片描述
如果PublicClass.java类和Run.java类不在同一个包中,则需要将PrivateClass内置声明public公开的。测试代码如下:

package test;

/**
 * @Author LiBinquan
 */
public class PublicClass {
    static private String userName;
    static private String passWord;
    static class PrivateClass {
        private String age;
        private String address;

        public String getAge() {
            return age;
        }

        public void setAge(String age) {
            this.age = age;
        }

        public String getAddress() {
            return address;
        }

        public void setAddress(String address) {
            this.address = address;
        }
        public void printPublicProperty(){
            System.out.println(userName + "  "+passWord);
        }
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }
}

运行类:

package test;

/**
 * @Author LiBinquan
 */
public class Run {
    public static void main(String[] args) throws InterruptedException {
        PublicClass publicClass = new PublicClass();
        publicClass.setUserName("AA");
        publicClass.setPassWord("aaa");
        System.out.println(publicClass.getUserName() + "  "+publicClass.getPassWord());
        PublicClass.PrivateClass privateClass = new PublicClass.PrivateClass();
        privateClass.setAge("13");
        privateClass.setAddress("addressValue");
        System.out.println(privateClass.getAge()+" "+privateClass.getAddress());
    }
}

输出:
在这里插入图片描述

接下来做几个测试:
1.内置类中有2个同步方法,但使用的却是不同的锁,打印的结果也是异步。

package test;

/**
 * @Author LiBinquan
 */
public class OutClass {
    static class Inner{
        public void method1(){
            synchronized ("锁1"){
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName()+" i = "+i);
                    try{
                        Thread.sleep(100);
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }
            }
        }
        public synchronized void method2(){
            for (int i = 0; i < 20; i++) {
                System.out.println(Thread.currentThread().getName()+" i = "+i);
                try{
                    Thread.sleep(100);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
    }
}

运行类:

package test;

/**
 * @Author LiBinquan
 */
public class Run {
    public static void main(String[] args) throws InterruptedException {
        final OutClass.Inner inner = new OutClass.Inner();
        Thread t1 = new Thread(new Runnable(){
            public void run (){
                inner.method1();
            }
        },"A");
        Thread t2 = new Thread(new Runnable(){
            public void run (){
                inner.method2();
            }
        },"B");
        t1.start();
        t2.start();
    }
}

输出:
在这里插入图片描述
由输出可得,持有不同的“对象监视器”,所以打印结果就是无序的。

2.同步代码块(class2)对class2上锁后,其他线程只能以同步的方式调式用class2中的静态同步方法。

package test;

/**
 * @Author LiBinquan
 */
public class OutClass {
    static class Inner1{
        public void method1(Inner2 class2){
            String threadName = Thread.currentThread().getName();
            synchronized (class2){
                System.out.println(threadName +"进入 Inner1 类中的 method1 方法");
                for (int i = 0; i < 10; i++) {
                    System.out.println("i = "+i);
                    try{
                        Thread.sleep(100);
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }
                System.out.println(threadName +"离开 Inner1 类中的 method1 方法");
            }
        }
        public synchronized void method2(){
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName +"进入 Inner1 类中的 method2 方法");
            for (int k = 0; k < 20; k++) {
                System.out.println(" k = "+k);
                try{
                    Thread.sleep(100);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
            System.out.println(threadName +"离开 Inner1 类中 method2 方法");
        }
    }
    static class Inner2{
        public synchronized void method1(){
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName + "进入 Inner2 类中的method1 方法");
            for (int i = 0; i < 10; i++) {
                System.out.println(" m = "+i);
                try{
                    Thread.sleep(100);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
            System.out.println(threadName + "离开入 Inner2 类中的method1 方法");
        }
    }
}

运行类:

package test;

/**
 * @Author LiBinquan
 */
public class Run {
    public static void main(String[] args) throws InterruptedException {
        final OutClass.Inner1 inner1 = new OutClass.Inner1();
        final OutClass.Inner2 inner2 = new OutClass.Inner2();
        Thread t1 = new Thread(new Runnable(){
            public void run (){
                inner1.method1(inner2);
            }
        },"A");
        Thread t2 = new Thread(new Runnable(){
            public void run (){
                inner1.method2();
            }
        },"B");
        Thread t3 = new Thread(new Runnable(){
            public void run (){
                inner2.method1();
            }
        },"C");
        t1.start();
        t2.start();
        t3.start();
    }
}

输出:
在这里插入图片描述

2.锁对象的改变

在将任何数据类型作为同步锁时,需要注意的是,是否有多个线程同时持有锁对象,如果同时持有相同的锁对象,则这些线程之间就是同步的;如果分别获得锁对象,这些线程就是异步的。

package test;

/**
 * @Author LiBinquan
 */
public class MyService {
    private String lock = "123";
    public void testMethod(){
        try{
            synchronized (lock){
                System.out.println(Thread.currentThread().getName()+" begin "+System.currentTimeMillis());
                lock = "456";
                Thread.sleep(2000);
                System.out.println(Thread.currentThread().getName()+" end   "+System.currentTimeMillis());
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

线程1:

package test;


/**
 * @Author LiBinquan
 */
public class ThreadTest1 extends Thread{

    private MyService service;
    public ThreadTest1(MyService service){
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.testMethod();
    }
}

线程2:

package test;


/**
 * @Author LiBinquan
 */
public class ThreadTest2 extends Thread{
    private MyService service;
    public ThreadTest2(MyService service){
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.testMethod();
    }
}

运行类:

package test;

/**
 * @Author LiBinquan
 */
public class Run {
    public static void main(String[] args) throws InterruptedException {
        MyService service = new MyService();
        ThreadTest1 a = new ThreadTest1(service);
        a.setName("A");
        ThreadTest2 b = new ThreadTest2(service);
        b.setName("B");
        a.start();
        Thread.sleep(50);
        b.start();
    }
}

输出:
在这里插入图片描述
因为50毫秒过后线程B取得的锁是“456”。
去掉Thread.sleep(50),代码如下:

package test;

/**
 * @Author LiBinquan
 */
public class Run {
    public static void main(String[] args) throws InterruptedException {
        MyService service = new MyService();
        ThreadTest1 a = new ThreadTest1(service);
        a.setName("A");
        ThreadTest2 b = new ThreadTest2(service);
        b.setName("B");
        a.start();
        b.start();
    }
}

输出:
在这里插入图片描述
这时线程1和线程2的锁都是“123”,虽然将随改成了“456”,但是结果还是同步的,因为1和2共同争抢的锁是“123”。
注意:只要对象不变,及时对象的属性被改变,运行的结果还是同步。测试代码如下,

package test;

/**
 * @Author LiBinquan
 */
public class Service {
    public void serviceMethodA(User user){
        synchronized (user){
            try{
                System.out.println(Thread.currentThread().getName());
                user.setUserName("abc");
                Thread.sleep(3000);
                System.out.println("end time = "+System.currentTimeMillis());
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

线程1:

package test;


/**
 * @Author LiBinquan
 */
public class ThreadTest1 extends Thread{

    private Service service;
    private User user;
    public ThreadTest1(Service service,User user){
        super();
        this.service = service;
        this.user = user;
    }
    @Override
    public void run() {
        service.serviceMethodA(user);
    }
}

线程2:

package test;


/**
 * @Author LiBinquan
 */
public class ThreadTest2 extends Thread{
    private Service service;
    private User user;
    public ThreadTest2(Service service,User user){
        super();
        this.service = service;
        this.user = user;
    }
    @Override
    public void run() {
        service.serviceMethodA(user);
    }
}

运行类:

package test;

/**
 * @Author LiBinquan
 */
public class Run {
    public static void main(String[] args) throws InterruptedException {
        try{
            Service service = new Service();
            User user = new User();
            ThreadTest1 t1 = new ThreadTest1(service,user);
            t1.setName("A");
            t1.start();
            Thread.sleep(50);
            ThreadTest2 t2 = new ThreadTest2(service,user);
            t2.setName("B");
            t2.start();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

输出:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值