public class MyObject {
public void methodA() {
synchronized(this){
//do something....
}
}
public class MyObject {
synchronized public void methodA() {
//do something....
}
synchronized public void methodB() {
//do some other thing
}
}
public class ThreadA extends Thread {
private MyObject object;
//省略构造方法
@Override
public void run() {
super.run();
object.methodA();
}
}
public class ThreadB extends Thread {
private MyObject object;
//省略构造方法
@Override
public void run() {
super.run();
object.methodB();
}
}
public class Run {
public static void main(String[] args) {
MyObject object = new MyObject();
//线程A与线程B 持有的是同一个对象:object
ThreadA a = new ThreadA(object);
ThreadB b = new ThreadB(object);
a.start();
b.start();
}
}
从上可以看出,本文中讲述的 synchronized 锁的范围是整个对象。如果一个类中有多个synchronized修饰的同步方法,且多个线程持有该类的同一个对象(该类的相同的对象),尽管它们调用不同的方法,各个方法的执行也是同步的。
如果各个同步的方法之间没有共享变量,或者说各个方法之间没有联系,但也只能同步执行,这会影响效率。
如果methodB()没有用synchronized 修饰,线程A在调用methodA()执行到第7行,更改了用户名,因某种原因(比如在第9行睡眠了)放弃了CPU。
此时,如果线程B去执行methodB(),那么读取到的用户名是线程A更改了的用户名(“a”),但是密码却是原来的密码(“bb”)。因为,线程A睡眠了,还没有来得及更改密码。但是,如果methodB()用synchronized修饰,那么线程B只能等待线程A执行完毕之后(即改了用户名,也改了密码),才能执行methodB读取用户名和密码。因此,就避免了数据的不一致性而导致的脏读问题。
public class Service {
public void testMethod(Object lock) {
try {
synchronized (lock) {
System.out.println("begin wait() ThreadName="
+ Thread.currentThread().getName());
lock.wait();
System.out.println(" end wait() ThreadName="
+ Thread.currentThread().getName());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void synNotifyMethod(Object lock) {
try {
synchronized (lock) {
System.out.println("begin notify() ThreadName="
+ Thread.currentThread().getName() + " time="
+ System.currentTimeMillis());
lock.notify();
Thread.sleep(5000);
System.out.println(" end notify() ThreadName="
+ Thread.currentThread().getName() + " time="
+ System.currentTimeMillis());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package 任务十__多线程;
/** * @author ${范涛之} * @Description * @create 2021-11-22 21:20 */
public class Test1 {
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized ("锁") {
System.out.println("t1 start");
try {
// t1 释放锁
"锁".wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1 end");
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized ("锁") {
System.out.println("t2 start");
try {
// 通知 t1 进入等待队列
"锁".notify();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("t2 end");
}
}
});
t1.start();
t2.start();
}
}
"锁".wait();
的时候,此时就会释放对象锁:"锁"
放弃CPU,然后开启了等待,此时的线程2执行到了 "锁".notify();
的时候,就会唤醒线程1,但是此时它并不立即释放锁,它还会继续执行自己知道临界区域:也就是这个线程的结束:“}”这个符号,此时其实线程2已经执行完了输出了t2 end,然后他释放了锁,这个时候线程1就可以拿到2刚刚释放的锁,开始执行自己后续的代码版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/justleavel/article/details/121480561
内容来源于网络,如有侵权,请联系作者删除!
"锁".wait();
的时候,此时就会释放对象锁:"锁"
放弃CPU,然后开启了等待,此时的线程2执行到了 "锁".notify();
的时候,就会唤醒线程1,但是此时它并不立即释放锁,它还会继续执行自己知道临界区域:也就是这个线程的结束:“}”这个符号,此时其实线程2已经执行完了输出了t2 end,然后他释放了锁,这个时候线程1就可以拿到2刚刚释放的锁,开始执行自己后续的代码