Java 多线程学习笔记 4 多线程共享数据

我们经常说某个变量是线程非安全的, 某个变量是线程安全, 这里 是否安全 针对的是类的实例变量, 如果是方法内部的私有变量, 不会存在这个问题

package smaug.cloud.provider.thread.t7;

/**
 * Created by naonao on 17/12/10.
 */
public class ThreadData {
    private int count = 0;
    public void add(String name) {
        try {
            if (name.equals("a")) {
                count = 10;
                Thread.sleep(2000);
            } else {
                count = 20;

            }
            System.out.println(name + "  got " + count);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package smaug.cloud.provider.thread.t7;

/**
 * Created by naonao on 17/12/9.
 */
public class Thread7A implements Runnable {
    private ThreadData threadData;

    public Thread7A(ThreadData data) {
        this.threadData = data;
    }

    @Override
    public void run() {
        this.threadData.add("a");
    }
}
package smaug.cloud.provider.thread.t7;

/**
 * Created by naonao on 17/12/10.
 */
public class Thread7B implements Runnable {
    private ThreadData threadData;
    public Thread7B(ThreadData threadData) {
        this.threadData = threadData;
    }

    @Override
    public void run() {
        this.threadData.add("v");
    }
}

写个test

package smaug.cloud.provider.thread.t7;

/**
 * Created by naonao on 17/12/10.
 */
public class Test7 {
    public static void main(String[] args) {
        ThreadData data = new ThreadData();
        Thread7B b = new Thread7B(data);
        Thread7A a = new Thread7A(data);
        Thread threadA = new Thread(a);
        Thread threadB = new Thread(b);

        threadA.start();
        threadB.start();
    }
}

得到的结论是

v  got 20
a  got 20

显然 此时的count 是非线程安全的, 就是因为在给count 赋值的时候冲突了,那么该如何避免呢?使用synchronized 关键字修饰

package smaug.cloud.provider.thread.t7;

/**
 * Created by naonao on 17/12/10.
 */
public class ThreadData {
    private int count = 0;
    public synchronized void add(String name) {
        try {
            if (name.equals("a")) {
                count = 10;
                Thread.sleep(2000);
                System.out.println(name + "  got " + count);
            } else {
                count = 20;
                System.out.println(name + "  got " + count);
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
a  got 10
v  got 20

结论是: 两个线程访问同一个对象中的同步方法的时候 一定是线程安全的,但是如果访问的是多个对象呢?

package smaug.cloud.provider.thread.t7;

/**
 * Created by naonao on 17/12/10.
 */
public class ThreadData {
    private int count = 0;
    public synchronized void add(String name) {
        try {
            if (name.equals("a")) {
                count = 10;
                System.out.println(name + "  set over");
                Thread.sleep(1000);
            } else {
                count = 20;
                System.out.println(name + "  set over");
            }

            System.out.println(name + "  got " + count);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package smaug.cloud.provider.thread.t7;

/**
 * Created by naonao on 17/12/10.
 */
public class Test7 {
    public static void main(String[] args) {
        ThreadData data = new ThreadData();
        ThreadData data2 = new ThreadData();
        Thread7B b = new Thread7B(data2);
        Thread7A a = new Thread7A(data);
        Thread threadA = new Thread(a);
        Thread threadB = new Thread(b);

        threadA.start();
        threadB.start();
    }
}

我们得到的输出结果是啥捏

a  set over
v  set over
v  got 20
a  got 10

两个线程去访问同一个类的两个不同实例的相同方法时,代码是异步执行的哦,synchronized 关键字取得锁是 对象锁,哪个线程优先获取到锁就可以优先执行,其他线程只能等待

总结

  1. A 线程持有object对象的Lock 锁, B线程可以异步的方式调用object对象中的非synchronized 方法
  2. A线程持有object对象的Lock锁,B如果在这时调用object对象中的synchronized 方法 则需等待,也就是同步
  3. synchronized 具有可重入锁的机制, 可以自己再次获取自己的内部锁
  4. 当线程执行的代码出现异常的时候, 会释放其持有的锁
  5. 同步锁不具备继承性

猜你喜欢

转载自blog.csdn.net/weixin_39526391/article/details/78766608