首先得明白什么是线程安全:
线程安全是编程中的术语,指某个函数 (计算机科学)、函数库在多线程环境中被调用时,能够正确地处理各个线程的局部变量,使程序功能正确完成。
这是维基百科里的资料,看完后还不是特别的明白。我自己的理解就是在多线程环境下,某块代码中访问的资源不会发生冲突。
写这篇笔记的起因是上周的支付宝电话面试中问了我一个线程安全的问题,就是有一个类,他的方法A是加了synchronized关键字的,然后分别创建这个类的两个实例,请问,当多个线程同时访问这两个实例中的方法A时synchronized会起作用吗?
当时我的回答还是很明确而自信的说“会”,今天觉得这个问题要好好研究一下,于是就写了代码做了一下测试,发现自己答错了,这或许是我面试失败的原因之一吧。代码贴出来:
class Thread2 extends Thread{
public void run() {
MyObj obj = new MyObj();
try {
obj.sayHello(3000);//3秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Thread3 extends Thread{
public void run() {
MyObj obj = new MyObj();
try {
obj.sayHello(1000);//1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyObj {
public synchronized void sayHello(int delay) throws InterruptedException{
Thread.sleep(delay);
System.out.println("delay" + delay);
}
}
public class ThreadTest {
public static void main(String[] args) throws Exception{
Thread2 t2 = new Thread2();
Thread3 t3 = new Thread3();
t2.start();//先让t2线程启动,因为t2要等待3秒,如果线程同步有作用的话t3会处理阻塞状态
t3.start();
}
}
代码中的MyObj类就是我用于测试的线程安全的对象,它包含了一个sayHello方法,他是带有synchronized关键字的。但测试结果却是
delay1000
delay3000
这说明关键字没有起作用,也说明了不同的对象实例synchronized方法时是线程不安全的。知道这个结果心里有些难过,只不过事情已经过去就当是学习了经验吧。
synchronized除了修饰方法外,还可以修饰代码块,那就试试看吧,写了一个新的类:
class MyObj2 {
private static Object lockObj = new Object();
public void sayHello(int delay) throws InterruptedException{
synchronized(lockObj){
Thread.sleep(delay);
System.out.println("delay" + delay);
}
}
}
用这个类做测试的结果:
delay3000
delay1000
这说明synchronized修改代码块时线程同步是起作用的,但这里要注意,采用synchronized代码块时,synchronized(lockObj)中的lockObj对象是一个静态对象,所以他们对应的锁是同一个,这就可以实现线程间的同步。如果换成synchronized(this)又无法同步。
于是就得想明白为什么会有这两种差别呢?原来JAVA中每个对象都对应一个锁,synchronized关键字是通过检查这个对象锁的状态来调度的。这下就明白了,原来关键就在于对象对应的那个锁,MyObj之所以不能同步是因为创建了两不同的对象实例,自然对应的对象锁就不同,而synchronized修饰的是方法时,其对应检查的是当前对象的锁,所以就会出现不同步的情况。
后来在网上查资料的同时也发现一个叫类锁的东东,通过类锁获得的类本身,是唯一的,那么就应该是可以同步了,代码如下:
class MyObj3 {
public synchronized static void sayHello(int delay) throws InterruptedException{
Thread.sleep(delay);
System.out.println("delay" + delay);
}
}
得到的结果
delay3000
delay1000
这说明已经同步了,synchronized+static一起修改时获得的是类锁,获得类本身,所以只有一个,那么同步自然有了效果。
分享到:
相关推荐
其中采用Java 的ExecutorService来进行线程池的方式实现多线程,模拟客户端多用户向同一服务器端发送请求....注意,此为学习笔记,可以作为参考学习使用,不建议商业使用或生产使用。 废话不多说,直接上代码。
Java线程:概念与原理 2 一、操作系统中线程和进程的概念 2 二、Java中的线程 3 三、Java中关于线程的名词解释 3 四、线程的状态转换和生命周期 4 Java线程:创建与启动 7 Java线程:线程名称的设定及获取 10 Java...
java线程学习笔记
Java 并发学习笔记: 进程和线程, 并发理论, 并发关键字, Lock 体系, 原子操作类, 发容器 & 并发工具, 线程池, 并发实践 Java是一种面向对象的编程语言,由Sun Microsystems于1995年推出。它是一种跨平台的...
java学习笔记2(多线程)java学习笔记2(多线程)
JUC学习笔记(Java多线程)
Java并发编程学习笔记,研究JAVA并发多线程编程的一本教程,使用并发技术可以开发出并行算法,充分利用多处理器的计算能力,避免硬件资源浪费。目前,在JAVA并发编程方面的论述系统且内容详实的技术资料不太多,Java...
java学习笔记5(java多线程)java学习笔记5(java多线程)
Java分布式应用学习笔记05多线程下的并发同步器
基于java的开发源码-java多线程反射泛型及正则表达式学习笔记和源码.zip 基于java的开发源码-java多线程反射泛型及正则表达式学习笔记和源码.zip 基于java的开发源码-java多线程反射泛型及正则表达式学习笔记和源码....
多线程学习笔记,通过平时的学习所做的一些笔记,希望对广大同仁有所帮助
java学习笔记大全:java内容介绍 java编程可以分成三个方向: 1、java se (j2se)桌面开发 java中的基础中的基础 2、java ee (j2ee)web开发 3、java me (j2me)手机开发 java se课程介绍 java面向对象编程(基础) java...
NULL 博文链接:https://baobeituping.iteye.com/blog/1190260
NULL 博文链接:https://itway.iteye.com/blog/1539359
Windows是一个多任务的系统,如果你使用的是windows 2000及其以上版本,...浏览器就是一个很好的多线程的例子,在浏览器中你可以在下载JAVA小应用程序或图象的同时滚动页面,在访问新页面时,播放动画和声音,打印文件等。
java学习笔记_多线程.txt,包括死锁的原因和解锁的方法。
1 java起源 2 java语言概述 3 简单(基本)数据类型 4 运算符:java有四大类运算符:算数运算、位运算、关系运算和逻辑运算 5 程序控制语句 6 介绍类:类是java的核心和本质 7 深入方法和类:方法重载、参数传递和递归...
花费了一上午的时候 写了一些demo。认识到四种线程池的区别。上传到csdn 供以后学习