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. 针对数据泵导出 (expdp) 和导入 (impdp)工具性能降低问题的检查表 (文档 ID 1549185.1)

    针对数据泵导出 (expdp) 和导入 (impdp)工具性能降低问题的检查表 (文档 ID 1549185.1) 文档内容 适用于: Oracle Database – Enterprise Edi ...

  2. tar 压缩指令基本用法

    压缩:tar -cjvf aaa.tar.bz2  www.test.com/  --exclude *.log(-j是用bz2压缩,-exclude是排除.log后缀的文件) c-创建 j-bzip ...

  3. 基于QProbe创建基本Android图像处理框架

    先来看一个GIF 这个GIF中有以下几个值得注意的地方 这个界面是基本的主要界面所应该在的地方.其右下角有一个“+”号,点击后,打开图像采集界面 在这个界面最上面的地方,显示的是当前图像处理的状态.( ...

  4. 20165310 NstSec2019 Week3 Exp1 逆向与Bof基础

    20165310 NstSec2019 Week3 Exp1 逆向与Bof基础 一.实验内容 实验目标 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用fo ...

  5. myeclise中创建maven web程序

    myeclipse自带了许多插件,因此使用频率很高,但是对maven框架下web程序似乎不是很好的支持,每次创建web程序总是会报一大堆的异常,因此特此记录一下如何在myeclipse下创建一个web ...

  6. RabbitMQ 入门指南——初步使用

    MQ的消息持久化 https://www.rabbitmq.com/tutorials/tutorial-two-java.html When RabbitMQ quits or crashes it ...

  7. (转)Spring Boot(二) & lombok

    (二期)5.springboot框架集成与lombok [课程五]springb...mbok.xmind0.1MB [课程五预习]spr...mbok.xmind0.1MB springboot的版 ...

  8. oracle 之 插入超长字段并包含&字符的处理方法

    oracle 在插入超长数据字符串时是默认转为varchar2类型,而这类型只有4000字节,即使通过oracle改变字符串类型为clob,也是在插入时默认转为varchar2类型. 处理方式:可以通 ...

  9. WEB安全学习二、注入工具 sqlmap的使用

    使用的是Kali Linux 系统,系统中默认的sqlmap 是安装好了的,电脑上没有安装sqlmap,自己百度  ,需要python的环境 使用 命令   sqlmap -h 可以查看   sqlm ...

  10. 解决: docker pull registry.access.redhat.com/rhel7/pod-infrastructure:latest

    直接获取 rpm文件 wget http://mirror.centos.org/centos/7/os/x86_64/Packages/python-rhsm-certificates-1.19.1 ...