1.方法内的变量为线程安全

  "非线程安全"问题存在于"实例变量"中,如果是方法内部的私有变量,则不存在"非线程安全"问题,所得结果也就是"线程安全"了。下面我们来编写一个"线程安全"的例子:

1.1 HasSelfPrivate类如下:

package edu.ymm.about_thread;

public class HasSelfPrivate {
public void add1(String username) {
try {
int num = 0; //这就是方法类的变量
if(username.equals("a")) {
num = 100;
System.out.println("a set over");
Thread.sleep(2000); //用来等待b }else {
num = 200;
System.out.println("b set over");
}
System.out.println(username + "num = " + num);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

1.2  创建一个ThreadA类:

package edu.ymm.about_thread;

public class ThreadA extends Thread {

	private HasSelfPrivate numself;
public ThreadA(HasSelfPrivate numself) {
super();
this.numself = numself;
} @Override
public void run() {
super.run();
numself.add1("a ");
} }

1.3 创建一个ThreadB类:

package edu.ymm.about_thread;

public class ThreadB extends Thread {

	private HasSelfPrivate numself;
public ThreadB(HasSelfPrivate numself) {
super();
this.numself = numself;
}
@Override
public void run() {
super.run();
numself.add1("b ");
}
}

1.4 来测试一下这个例子:

package edu.ymm.about_thread;

public class Test {

	public static void main(String[] args) {

		HasSelfPrivate hPrivate = new HasSelfPrivate();
ThreadA threadA = new ThreadA(hPrivate);
threadA.start();
ThreadB threadB =new ThreadB(hPrivate);
threadB.start();
} }

执行结果如下:

可见,方法中的变量不存在非线程安全问题,永远是线程安全的。原因就是方法内部的变量是私有的。

2.实例变量非线程安全

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

  (2):用线程访问的对象中如果有多个实例变量,则运行的结果有可能出现交叉情况。

  (3):如果对象仅有1个实例变量,则可能出现覆盖的情况。

下面举一个例子:

2.1 HasSelfPrivate类如下:

package edu.ymm.about_thread1;

public class HasSelfPrivate {
private int num = 0;
public void add1(String username) {
try {
if(username.equals("a")) {
num = 100;
System.out.println("a set over");
Thread.sleep(3000); //用来等待b
}else {
num = 200;
System.out.println("b set over");
}
System.out.println(username + "num = " + num); } catch (InterruptedException e) {
e.printStackTrace();
}
}
}

2.2 创建一个ThreadA类:

package edu.ymm.about_thread1;

public class ThreadA extends Thread {

	private HasSelfPrivate numself;
public ThreadA(HasSelfPrivate numself) {
super();
this.numself = numself;
} @Override
public void run() {
super.run();
numself.add1("a ");
} }

2.3创建一个ThreadB类:

package edu.ymm.about_thread1;

public class ThreadB extends Thread {

	private HasSelfPrivate numself;
public ThreadB(HasSelfPrivate numself) {
super();
this.numself = numself;
}
@Override
public void run() {
super.run();
numself.add1("b ");
}
}

2.4来测试一下这个例子:

package edu.ymm.about_thread1;

public class Test {

	public static void main(String[] args) {

		HasSelfPrivate hPrivate = new HasSelfPrivate();
ThreadA threadA = new ThreadA(hPrivate);
threadA.start();
ThreadB threadB =new ThreadB(hPrivate);
threadB.start();
} }

结果如下:

  上述就是所谓的“非线程安全”的一个例子。a的值不是我们预期的100了。要解决这种现象,只需要在a和b共同访问的方法前加上“synchronized”就可以了。

更新这个类后:

package edu.ymm.about_thread1;

public class HasSelfPrivate {
private int num = 0;
synchronized public void add1(String username) {
try {
if(username.equals("a")) {
num = 100;
System.out.println("a set over");
Thread.sleep(2000); //用来等待b
}else {
num = 200;
System.out.println("b set over");
}
System.out.println(username + " num=" + num); } catch (InterruptedException e) {
e.printStackTrace();
}
}
}

再执行结果为:

所以,在两个线程访问同一个对象中的同步方法(synchronized)时一定是线程安全的。

3.多个对象多个锁

我们来改动一点:将测试中产生两个实例对象。

3.1 HasSelfPrivate类如下:

package edu.ymm.about_thread2;

public class HasSelfPrivate {
private int num = 0;
synchronized public void add1(String username) {
try {
if(username.equals("a")) {
num = 100;
System.out.println("a set over");
Thread.sleep(2000); //用来等待b
}else {
num = 200;
System.out.println("b set over");
}
System.out.println(username + " num=" + num); } catch (InterruptedException e) {
e.printStackTrace();
}
}
}

上面代码中有同步方方法add1,说明此方法应该被顺序调用。

3.2 创建一个ThreadA类:

package edu.ymm.about_thread2;

public class ThreadA extends Thread {

	private HasSelfPrivate numself;
public ThreadA(HasSelfPrivate numself) {
super();
this.numself = numself;
} @Override
public void run() {
super.run();
numself.add1("a");
} }

3.3创建一个ThreadB类:

package edu.ymm.about_thread2;

public class ThreadB extends Thread {

	private HasSelfPrivate numself;
public ThreadB(HasSelfPrivate numself) {
super();
this.numself = numself;
}
@Override
public void run() {
super.run();
numself.add1("b");
}
}

3.4来测试一下这个例子:

package edu.ymm.about_thread2;

public class Test {

	public static void main(String[] args) {

		HasSelfPrivate hPrivate1 = new HasSelfPrivate();
HasSelfPrivate hPrivate2 = new HasSelfPrivate();
ThreadA threadA = new ThreadA(hPrivate1);
threadA.start();
ThreadB threadB =new ThreadB(hPrivate2);
threadB.start();
} }

执行结果如下:

上述示例是两个线程分别访问一个类的两个不同实例的相同名称的同步方法,效果却是异步的方式运行的。本示例由于创建了2个业务对象,在系统中产生了两个锁,所以运行结果是异步的,打印的效果就是先打印b再打印a。

关键字synchronized取得的锁都是对象锁,而不是把一段代码或方法(函数)当作锁,所以在上面的示例中,哪个线程先执行带synchronized关键字的方法,哪个线程就持有该方法所属对象的锁Lock,那么其他线程只能呈等待状态,前提是多个线程访问的是同一个对象。

但是如果多个线程访问多个对象,则JVM会创建多个锁。

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

  1. synchronized同步方法《二》

    1.synchronized方法和锁对象 (1).验证线程锁的是对象 代码如下: 1.1创建一个MyObject类: package edu.ymm.about_thread4; public cla ...

  2. synchronized同步方法

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

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

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

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

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

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

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

  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. uml类图和er图中主外键的表示区别

    在er图也就是数据库中,无论是mysql/oracle都是从表引用主表的pk作为外键. 而在uml类图表示法中,他们的顺序则刚好相反,从主对象导向到子对象,如下: 主体是资金借款方,征信信息和资金借款 ...

  2. rabbitmq heartbeat missing with heartbeat = N seconds原因总结

    一直以来,在我们大规模使用rabbitmq的服务端应用中,都没有出现rabbitmq心跳超时而造成的的影响,反倒是在rabbitmq-cpp客户端出现过很多次该问题,一直以为客户端lib实现的问题(不 ...

  3. opencv学习之路(12)、图像滤波

    一.图像滤波简介 二.方框滤波——boxFilter() #include<opencv2/opencv.hpp> using namespace cv; void main(){ Mat ...

  4. JQuery 实现 倒计时 按钮具体方法

    <head> <title>test count down button</title> <script src="http://ajax.aspn ...

  5. JS实现对数器

    对数器的概念和使用 对数器一般用于验证你写的算法是否正确,因为自己写的测试用例可能写的考虑不够全面. 0.有一个你想测试的方法a 1.实现一个绝对正确但是时间复杂度不好的方法b 2.实现一个随机样本产 ...

  6. InstallShield 2015 生成单个EXE包和 MSI包

    生成EXE包: 生成MSI包:

  7. Python3基础 dict fromkeys 多个键对应相同的值

             Python : 3.7.0          OS : Ubuntu 18.04.1 LTS         IDE : PyCharm 2018.2.4       Conda ...

  8. MongoDB 创建索引及其他

    索引 以提升查询速度 测试:插入十万条数据到数据库中 for(i=0;i<100000;i++){db.t255.insert({name:'test'+i,age:i})} db.t1.fin ...

  9. SP6779 GSS7

    GSS7解题报告 前言 唔,有点恶心哪,废了两个多小时debug 思路 很容易看出傻子都知道,这个是树链剖分+线段树的裸题,只不过是恶心了点,这里重点讲一下细节问题 线段树 做过GSS系列的都应该很熟 ...

  10. .NET Standard vs. .NET Core

    What is the difference between .NET Core and .NET Standard Class Library project types? Answer1 When ...