接上一篇synchronized同步方法
关键字synchronized取得的锁都是对象锁,而不是把一段代码或方法当作锁。对于多个线程同时执行一个对象的一个同步方法,哪个线程先执行带synchronized关键字的方法,哪个线程就持有了该方法所属对象的锁Lock,那么其他线程只能呈等待状态。
2. 如何通过synchronized关键字解决脏读
代码:
package testSynchronized;
public class PublicVar {
public String username ="A";
public String password = "AA";
synchronized public void setValue(String username,String password){
try{
this.username = username;
Thread.sleep(5000);
this.password = password;
System.out.println("setValue method thread name = "+Thread.currentThread().getName()+" username = "+username
+", password = "+password);
}catch(InterruptedException e){
e.printStackTrace();
}
}
public void getValue(){
System.out.println("getValue method thread name ="+Thread.currentThread().getName()+
" username = "+username +", password = "+password);
}
}
package testSynchronized;
public class ThreadA extends Thread {
private PublicVar publicVar;
public ThreadA(PublicVar publicVar){
this.publicVar = publicVar;
}
@Override
public void run() {
publicVar.setValue("B", "BB");
}
}
package testSynchronized;
public class Test {
public static void main(String[] args) {
PublicVar publicVar = new PublicVar();
ThreadA threadA = new ThreadA(publicVar);
threadA.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
publicVar.getValue();
}
}
运行结果:
getValue method thread name =main username = B, password = AA//出现脏读
setValue method thread name = Thread-0 username = B, password = BB
若将getValue() 前加上synchronized关键字,就不会出现这种情况了。
sunchronized public void getValue(){
System.out.println("getValue method thread name ="+Thread.currentThread().getName()+
" username = "+username +", password = "+password);
}
运行结果:
setValue method thread name = Thread-0 username = B, password = BB
getValue method thread name =main username = B, password = BB
当A线程调用anyObject对象的同步方法(加入synchronized关键字)X时,A线程就获得了X方法锁,更准确的将是:获得了X方法所属对象的锁,所以其他线程必须等到A线程执行完毕才可以调用X方法,但是B线程可以随意调用其他的非synchronized同步方法。
当A线程调用了anyObject对象的同步方法时X时,A线程就获得了X方法所属对象的锁,所以其他线程必须等到A线程执行完毕才可以调用X方法,二如果B线程调用了其他的同步方法(不是X方法),也必须等到A线程将X方法执行完,也就是A线程释放了对象锁后才可以调用。
3.synchronized 锁重入
关键字synchronized拥有锁重入的功能,也就是在使用synchronized时,当一个线程得到了一个对象锁后,再次请求此对象锁时是可以再次得到的该锁的。这也证明在一个synchronized方法/块的内部调用本类的其他synchronized方法/块时,是永远可以得到锁的。
代码:
package testSynchronized;
public class Service {
synchronized public void service1(){
System.out.println("service1");
service2();
}
synchronized public void service2() {
System.out.println("service2");
service3();
}
synchronized public void service3() {
System.out.println("service3");
}
}
package testSynchronized;
public class Main {
public static void main(String[] args) {
Thread thread1 = new Thread(){
@Override
public void run() {
super.run();
Service service = new Service();
service.service1();
}
};
thread1.start();
}
}
运行结果:
service1
service2
service3
“可重入锁”的概念是:自己可以再次获取自己的内部锁。 例如:由1个线程获得了某个对象的锁,此时这个对象锁还没有被释放,当该线程再次想要获取这个对象锁时是可以获取的,如果不可获取锁重入的话,就会造成死锁。
可重入锁也支持在父子类继承的环境中。
package testSynchronized;
public class Parent {
public int i = 10;
synchronized public void operateParentMethod(){
try {
i--;
System.out.println("Parent print i = "+i);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package testSynchronized;
public class Son extends Parent {
synchronized public void operateSonMethod(){
try {
while(i >0){
i--;
System.out.println("Son print i = "+i);
Thread.sleep(1000);
this.operateParentMethod();//子类在自己的同步方法中调用父类的同步方法
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package testSynchronized;
public class MyThread extends Thread {
@Override
public void run() {
super.run();
Son son = new Son();
son.operateSonMethod();
}
}
package testSynchronized;
public class Run {
public static void main(String[] args) {
Thread thread = new MyThread();
thread.start();
}
}
运行结果:
Son print i = 9
Parent print i = 8
Son print i = 7
Parent print i = 6
Son print i = 5
Parent print i = 4
Son print i = 3
Parent print i = 2
Son print i = 1
Parent print i = 0
运行结果说明:当存在父子类继承关系时,子类完全可以通过“可重入锁”调用父类的同步方法。
synchronized同步方法2
最新推荐文章于 2024-02-28 17:17:38 发布