- 方法内的变量线程安全(方法内部变量具有私有性)
- 实例变量(类下的直接定义的变量)非线程安全(可通过对操作方法加锁解决)
class MyEntity6 {
private int num = 10;
// 加锁解决线程不安全问题
synchronized public void add(int addNum) {
this.num += addNum;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("num = " + num);
}
}
public class StudyThreads6线程安全 {
public static void main(String[] args) {
MyEntity6 myEntity6 = new MyEntity6();
Thread t1 = new Thread() {
@Override
public void run() {
myEntity6.add(100);
}
};
Thread t2 = new Thread() {
@Override
public void run() {
myEntity6.add(100);
}
};
t1.start();
t2.start();
}
}
资源不共享时候无需加锁
当资源不共享时候,各线程有自己的相应的变量,不加锁多线程之间也不会相互影响。
脏读(写加锁可以解决变量交叉造成的不安全的问题,读变量时候也可能造成不安全)- 脏读即在读的时候此时的变量已经被其他线程更改了
- 可以通过在读方法上加锁来解决(即在读和写方法上都加锁)
- synchronize锁的是对象,当共享实例变量时候传入的是同一个对象,synchronize会对这个对象加锁。
- 在被锁的方法中调用本类中其他加锁的方法时候,锁会自动重入进来
- 锁重入支持在父子继承
- 如果不能锁重入则会造成死锁(当前方法持有锁,方法内部调用的方法请求锁)
当出现异常时候锁会自动释放
同步不能继承父类方法已经同步之后,子类方法需要重写加入synchronize关键字才能实现同步功能,否则不是同步方法。
synchronize(对象),针对对象加锁,如果对象不一样则相应的方法或代码块可以异步执行- synchronize针对对象加锁,传入对象不一样则锁互不影响
- synchronize(this) {}对当前对象加锁
- synchronize修饰静态方法时,是对拥有方法的class上锁;而synchronize关键字加到非static方法上时,是给对象上锁。(代码如下)
- 对class上锁对所有实例都起作用
- synchronize(x.class) 与synchronize static作用一样,都是给对象上锁
printA() printB() 方法是对class加锁,printC()是给对象上锁。锁对象不一样 C与AB不同步:
// synchronize修饰静态方法加锁是对class上锁
// synchronize修饰非静态方法是对对象上锁
// 验证上锁不同如下
class Service {
public synchronized static void printA() {
try {
System.out.println("线程名字:" + Thread.currentThread().getName() + "在 " + System.currentTimeMillis() +
" 进入A方法。");
Thread.sleep(3000);
System.out.println("线程名字:" + Thread.currentThread().getName() + "在 " + System.currentTimeMillis() +
" 离开A方法。");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized static void printB() {
try {
System.out.println("线程名字:" + Thread.currentThread().getName() + "在 " + System.currentTimeMillis() +
" 进入B方法。");
Thread.sleep(3000);
System.out.println("线程名字:" + Thread.currentThread().getName() + "在 " + System.currentTimeMillis() +
" 离开B方法。");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void printC() {
try {
System.out.println("线程名字:" + Thread.currentThread().getName() + "在 " + System.currentTimeMillis() +
" 进入C方法。");
Thread.sleep(3000);
System.out.println("线程名字:" + Thread.currentThread().getName() + "在 " + System.currentTimeMillis() +
" 离开C方法。");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class StudyThreads7synchronize给静态方法加锁 {
public static void main(String[] args) {
Service myService = new Service();
Thread threadA = new Thread(() -> myService.printA());
Thread threadB = new Thread() {
@Override
public void run() {
myService.printB();
}
};
Thread threadC = new Thread() {
@Override
public void run() {
myService.printC();
}
};
threadA.setName("A");
threadB.setName("B");
threadC.setName("C");
threadA.start();
threadB.start();
threadC.start();
}
}
输出结果:



