Android 第一周

课前作业:

1. 问题一:

当前有一个类 A

public class A {

    public synchronized void a() {

    }

    public synchronized void b() {

    }

}

然后创建两个对象:

A a1 = new A();
A a2 = new A();

然后在两个线程中并发访问如下代码:

Thread1 中执行 a1.a();
Thread2 中执行 a2.a();

请问二者能否构成线程同步?

2. 如果类 A 变成下面那样呢?

public class A {

    public static synchronized void a() {

    }

    public static synchronized void b() {

    }

}

正式开始:

理解 Java 中的 Synchronized 关键字

1.方法内的变量是线程安全的

方法内部的私有变量不存在非线程安全问题

2.实例变量是非线程安全的

多个线程访问同一个对象中的实例变量,则有可能出现非线程安全的问题

GuessIsAdult.java:根据年龄判断是否成年

/**
 * 根据年龄是否大于 18 岁判断是否成年
 */
public class GuessIsAdult {

    /**
     * 是否成年 成年了:age >= 18 未成年:age < 18
     */
    private boolean isAdult;

    public void isAdult(int age) {
        try {
            if (age >= 18) {
                isAdult = true;
                Thread.sleep(2000);
            } else {
                isAdult = false;
            }

            if (isAdult) {
                System.out.println("年龄" + age + ",我成年啦");
            } else {
                System.out.println("年龄" + age + ",我未成年");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    static class ThreadGuessA extends Thread {

        private GuessIsAdult guessIsAdult;

        public ThreadGuessA(GuessIsAdult guessIsAdult) {
            this.guessIsAdult = guessIsAdult;
        }

        @Override
        public void run() {
            guessIsAdult.isAdult(19);
        }

    }

    static class ThreadGuessB extends Thread {

        private GuessIsAdult guessIsAdult;

        public ThreadGuessB(GuessIsAdult guessIsAdult) {
            this.guessIsAdult = guessIsAdult;
        }

        @Override
        public void run() {
            guessIsAdult.isAdult(17);
        }

    }

}

测试类 GuessMain.java

public class GuessMain {

    public static void main(String[] args) {
        GuessIsAdult guessIsAdult = new GuessIsAdult();
        ThreadGuessA aThread = new ThreadGuessA(guessIsAdult);
        aThread.start();
        ThreadGuessB bThread = new ThreadGuessB(guessIsAdult);
        bThread.start();
    }

}

测试结果:
实例变量非线程安全

问题原因:

在 GuessIsAdult.isAdult() 方法中,当一个人年龄 19,则在线程睡眠 2s 之前,isAdult 还是个 true,2s 过后 isAdult 则早被年龄 17 那个人改成 false 了,显然这不安全的

解决办法:

只需要在 GuessIsAdult.isAdult() 方法最前面添加 synchronized 关键字即可

结论:

1.当 A 线程调用某个对象的 synchronized 方法 X 时,A 线程获得了 X 方法的对象锁,其它线程必须等 A 线程执行完毕才可以调用 X 方法,由于是对象锁,即使其它线程调用 synchronized 的非 X 方法,也必须等 A 线程把 X 方法执行完毕,等到释放了对象锁之后才可以调用该对象中的任意的 synchronized 方法

2.当 A 线程调用某个对象的 synchronized 方法 X 时,B 线程可随意调用该对象的非 synchronized 方法

作业答案:

1.不能同步,new 了 2 个对象,就有2 个锁,则方法异步执行
2.能同步,synchronized 关键字加到静态方法前,获取的锁是类对应的锁,该锁对类的所有对象都有效,则方法同步执行

猜你喜欢

转载自blog.csdn.net/qq_21586317/article/details/80153382