我们经常说某个变量是线程非安全的, 某个变量是线程安全, 这里 是否安全 针对的是类的实例变量, 如果是方法内部的私有变量, 不会存在这个问题
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 关键字取得锁是 对象锁,哪个线程优先获取到锁就可以优先执行,其他线程只能等待
总结
- A 线程持有object对象的Lock 锁, B线程可以异步的方式调用object对象中的非synchronized 方法
- A线程持有object对象的Lock锁,B如果在这时调用object对象中的synchronized 方法 则需等待,也就是同步
- synchronized 具有可重入锁的机制, 可以自己再次获取自己的内部锁
- 当线程执行的代码出现异常的时候, 会释放其持有的锁
- 同步锁不具备继承性