首页 技术 正文
技术 2022年11月23日
0 收藏 505 点赞 2,591 浏览 5248 个字

1.synchronized方法和锁对象

(1)、验证线程锁的是对象

代码如下:

1.1创建一个MyObject类:

package edu.ymm.about_thread4;public class Myobject {public void methodA() {
try {
System.out.println("begin methodA threadName="
+ Thread.currentThread().getName());
Thread.sleep(5000);
System.out.println("end");
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}

1.2创建一个ThreadA类:

package edu.ymm.about_thread4;public class ThreadA extends Thread {private Myobject myobject;
public ThreadA(Myobject myobject) {
super();
this.myobject = myobject;
}@Override
public void run() {
super.run();
myobject.methodA();
}}

1.3创建一个ThreadB类:

package edu.ymm.about_thread4;public class ThreadB extends Thread {private Myobject myobject;
public ThreadB(Myobject myobject) {
super();
this.myobject = myobject;
}@Override
public void run() {
super.run();
myobject.methodA();
}}

1.4创建一个Test测试类:

package edu.ymm.about_thread4;public class Test {public static void main(String[] args) {Myobject myobject = new Myobject();
ThreadA threadA = new ThreadA(myobject);
threadA.setName("a");ThreadB threadB =new ThreadB(myobject);
threadB.setName("b");
threadA.start();
threadB.start();
}}

1.5结果如下:

synchronized同步方法《二》

更改MyObject类后:

package edu.ymm.about_thread4;public class Myobject {synchronized public void methodA() {
try {
System.out.println("begin methodA threadName="
+ Thread.currentThread().getName());
Thread.sleep(5000);
System.out.println("end");
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}

其他三个类不变,结果如下:

synchronized同步方法《二》

通过上面的代码得到结论,调用关键字synchronized声明的方法一定是排队运行的。另外需要牢牢记住“共享”,因为只有共享资源的读写访问才需要同步化,如果不是共享资源,那么根本就没有同步的必要!

 下面我们来看另一种情况:

(2)、其他方法被调用的效果,以及查看Lock锁对象的效果:

2.1继续创建一个MyObject类:

package edu.ymm.about_thread4;public class Myobject {synchronized public void methodA() {
try {
System.out.println("begin methodA threadName="
+ Thread.currentThread().getName());
Thread.sleep(5000);
System.out.println("end endTime" + System.currentTimeMillis());
}catch (InterruptedException e) {
e.printStackTrace();
}
}
public void methodB() {
try {
System.out.println("begin methodB threadName="
+ Thread.currentThread().getName()
+ " begin Time" + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("end");
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}

2.2继续创建一个ThreadA类:

package edu.ymm.about_thread4;public class ThreadA extends Thread {private Myobject myobject;
public ThreadA(Myobject myobject) {
super();
this.myobject = myobject;
}@Override
public void run() {
super.run();
myobject.methodA();
}}

2.3继续创建一个ThreadB类:

package edu.ymm.about_thread4;public class ThreadB extends Thread {private Myobject myobject;
public ThreadB(Myobject myobject) {
super();
this.myobject = myobject;
}@Override
public void run() {
super.run();
myobject.methodB();
}}

2.4继续创建一个Test类:

package edu.ymm.about_thread4;public class Test {public static void main(String[] args) {Myobject myobject = new Myobject();
ThreadA threadA = new ThreadA(myobject);
threadA.setName("a");ThreadB threadB =new ThreadB(myobject);
threadB.setName("b");
threadA.start();
threadB.start();
}}

结果如下:

synchronized同步方法《二》

通过这个例子我们可以得到的结论是:

(1)A线程先持有Object对象的Lock锁,B线程可以以异步的方式调用Object对象中的非synchronized类型的方法。

(2)A线程先持有Object对象的Lock锁,B线程如果在这时调用Object对象中的synchronized类型的方法则需要等待,也就是同步!

 2.脏读

  在上面1的例子中已经实现多个线程调用同一个方法时,为了避免数据出现交叉的情况,使用synchronized关键字来进行同步。虽然在赋值时进行了同步。但是在取值时有可能出现一些意料不到的意外,这种情况就是脏读。发生脏读的情况是在读取实例变量时,此值已经被其他线程更改过了。

(1)创建一个publicVar类:

package edu.ymm.about_thread5;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);
}
}

(2)创建一个ThreadA类:

package edu.ymm.about_thread5;public class ThreadA extends Thread {private PublicVar publicVar;
public ThreadA(PublicVar publicVar) {
super();
this.publicVar = publicVar;
}@Override
public void run() {
super.run();
publicVar.setValue("B", "BB");
}}

(3)创建一个Test类:

package edu.ymm.about_thread5;public class Test {public static void main(String[] args) {
try {
PublicVar publicVar = new PublicVar();
ThreadA threadA = new ThreadA(publicVar);
threadA.start();
Thread.sleep(2000);
publicVar.getValue();
}catch (InterruptedException e) {
e.printStackTrace();
}
}}

执行结果如下:

synchronized同步方法《二》

上述的结果中已经出现了脏读,username为B的密码成了“AA”。原因就是public void getValue()方法不是同步的,所以在任何时候都可以调用。解决办法就是加synchronized:

package edu.ymm.about_thread5;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();
}
}
synchronized public void getValue() {
System.out.println("getValue method thread name="
+ Thread.currentThread().getName()+ " username "
+ username + " password " + password);
}
}

改后结果为:

synchronized同步方法《二》

可见,方法setValue()和方法getValue()被依次执行。通过这个例子不仅要知道脏读是通过synchronized解决的。还得明白以下几点:

  当A线程调用anyObject对象加入synchronized 关键字的X方法时,A线程就获得了x方法锁,更准确地讲,是获得了对象的锁,所以其他线程必须等A线程执行完毕才可以调用x方法,但B线程可以随意调用其他的非synchronized同步方法。

  当A线程调用anyobject对象加入synchronized关键字的X方法时,A线程就获得了X方法所在对象的锁,所以其他线程必须等A线程执行完毕才可以调用X方法,而B线程如果调用声明了synchronized关键字的非X方法时,必须等A线程将X方法执行完,也就是释放对象锁后才可以调用。这时A线程已经执行了一个完整的任务,也就是说usemame和password这两个实例变量已经同时被赋值,不存在脏读的基本环境。

  脏读一定会出现操作实例变量的情况下,这就是不同线程 “争抢”实例变量的结果。

微信扫一扫

支付宝扫一扫

本文网址:https://www.zhankr.net/141114.html

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:877 阅读:6,217
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:806 阅读:4,049
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:566 阅读:4,849
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:732 阅读:4,785
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:5,873
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:3,567
助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:8:00-16:00

客服电话

400-888-8888

客服邮箱

ceotheme@ceo.com

扫描二维码

关注微信公众号

扫描二维码

手机访问本站