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结果如下:

更改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声明的方法一定是排队运行的。另外需要牢牢记住“共享”,因为只有共享资源的读写访问才需要同步化,如果不是共享资源,那么根本就没有同步的必要!

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

(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();
} }

结果如下:

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

(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();
}
} }

执行结果如下:

上述的结果中已经出现了脏读,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);
}
}

改后结果为:

可见,方法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这两个实例变量已经同时被赋值,不存在脏读的基本环境。

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

synchronized同步方法《二》的更多相关文章

  1. synchronized同步方法

    “非线程安全”其实会在多个线程对同一个对象中的实例变量进行并发访问的时候产生,产生的后果是脏读,也就是取到的数据是被更改过的.而“线程安全”就是以获得的实例变量的值是经过同步处理的,不会出现脏读的现象 ...

  2. 四、java多线程核心技术——synchronized同步方法与synchronized同步快

    一.synchronized同步方法 论:"线程安全"与"非线程安全"是多线程的经典问题.synchronized()方法就是解决非线程安全的. 1.方法内的变 ...

  3. java多线程(二)——锁机制synchronized(同步方法)

    synchronized Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码.当两个并发线程访问同一个对象object中 ...

  4. 深入理解使用synchronized同步方法和同步代码块的区别

    一.代码块和方法之间的区别 首先需要知道代码块和方法有什么区别: 构造器和方法块,构造器可以重载也就是说明在创建对象时可以按照不同的构造器来创建,那么构造器是属于对象,而代码块呢他是给所有的对象初始化 ...

  5. synchronized同步方法《一》

    1.方法内的变量为线程安全 "非线程安全"问题存在于"实例变量"中,如果是方法内部的私有变量,则不存在"非线程安全"问题,所得结果也就是&q ...

  6. 二十二 synchronized同步方法

    一 Synchronized锁: 1 synchronized取得的锁都是对象锁,而不是把一段代码或方法加锁. synchronized是给该方法的实例对象加锁.如果多个线程访问的是同一个对象  的s ...

  7. synchronized同步方法和同步代码块的区别

    同步方法默认使用this或者当前类做为锁. 同步代码块可以选择以什么来加锁,比同步方法更精确,我们可以选择只有会在同步发生同步问题的代码加锁,而并不是整个方法. 同步方法使用synchronized修 ...

  8. 58、synchronized同步方法

    线程安全问题 先看下面代码出现的问题: 定义一个Task类,里面有一个成员变量和一个有boolean类型参数的方法,方法内部会根据传入参数修改成员变量的值. package com.sutaoyu.T ...

  9. java synchronized静态同步方法与非静态同步方法,同步语句块

    摘自:http://topmanopensource.iteye.com/blog/1738178 进行多线程编程,同步控制是非常重要的,而同步控制就涉及到了锁. 对代码进行同步控制我们可以选择同步方 ...

随机推荐

  1. 个人小爱好:Operating System: three easy pieces第6章第5节——总结

    总结 我们讨论了实现CPU虚拟化的部分底层机制,及我们统称为直接执行(direct execution)的一组技术.基本的思想十分简单明了:直接在CPU上运行你想运行的代码,但是你先得确保将硬件设置好 ...

  2. VLAN之间通信-三层交换

    实验目的 VLAN之间通信-三层交换 掌握配置VLANIF接口的方法 理解数据包跨VLAN路由的原理 掌握测试多层交换网络连通性的方法 实验原理 三层交换机在原有二层交换机的基础之上增加了路由功能,同 ...

  3. 内置委托func

    1.p=>p.CTName,其中p是此委托入参,p.CTName是返回值 2. 3.调用委托的方法

  4. Hash算法和一致性Hash算法

    Hash算法 我们对同一个图片名称做相同的哈希计算时,得出的结果应该是不变的,如果我们有3台服务器,使用哈希后的结果对3求余,那么余数一定是0.1或者2,正好与我们之前的服务器编号相同,如果求余的结果 ...

  5. vue-cli 搭建的项目,无法用本地IP访问

    项目是用vue-cli搭建的,是基于移动端的,需要在手机上测试的时候发现用ip访问不了,用localhost是可以访问的,网上查资料的解决办法(此为Mac机子的解决办法): 在config文件里面的i ...

  6. kubectl批量删除pvc

    #!/bin/bashkubectl get pvc |grep hub > tmp.txtcat tmp.txt |awk '{split($0,a," ");print ...

  7. 归并排序(Python实现)

    目录 1. 归并排序--while版本 2. 测试用例 3. 算法时间复杂度分析 1. 归并排序--while版本 def merge_sort_while(b_list): '''归并排序--whi ...

  8. 【UML】-NO.45.EBook.5.UML.1.005-【UML 大战需求分析】- 通讯图(Communication Diagram)

    1.0.0 Summary Tittle:[UML]-NO.45.EBook.1.UML.1.005-[UML 大战需求分析]- 通讯图(Conmunication Diagram) Style:De ...

  9. CentOS6.5安装pip

    首先重要的事情说三遍,因为可能有程序依赖目前的python2环境,比如yum: 不要动现有的python2环境! 不要动现有的python2环境! 不要动现有的python2环境! 如果你动了,yum ...

  10. shell脚本遍历当前目录下以数字命名的目录,并打印

    #!/bin/bash single='' #定义以个位数为目录的集合double='' #定位十位数为目录的集合#按照需要可以根据实际情况再定义以百位数为目录的集合 for dir in `ls - ...