今天去淘宝一面……好不容易有次笔试不错可以去面试,结果太悲剧了,面试官提的很多问题都答不上,果然得到回家等通知的回答。没办法,只好收拾心情继续准备下间公司了555555我真的很想去杭州啊!!
其中有一题问到java的同步问题,我只是知道一点点,囫囵吞枣的忽悠过去,当然忽悠不了面试官。
google了一下,还真是他妈的简单啊,这样都不会真活该被刷!
Java线程安全同步解决方案
1、 问题描述:
如果一个资源或对象可能被多个线程同时访问,它就是一个共享资源;例如类的成员变量,包括类变量和实例变量,再比如对一个文件进行写操作等。一般情况下,对共享资源的访问需要考虑线程安全的问题。
如果一个对象的完整生命周期只在一个线程内,则不需要考虑线程安全,例如一个局部变量。下面为一个示例代码:
- public class C1 {
- public static java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd");
- //其他代码
-
}
假如在一个JSP中这样的去调用:
- <a.jsp>:
- <%
- Java.util.Date date = C1.sdf.parse(“2003-4-15”);
-
%>
则这样的代码不是线程安全的。因为java.text.SimpleDateFormat不是线程安全的,a.jsp中的代码将会有若干个线程同时执行,而都访问的是同一个线程不安全的对象,这样就不是一个线程安全的代码。正确的写法应该如下:
- <a.jsp>:
- <%
- java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd");
- Java.util.Date date = sdf.parse(“2003-4-15”);
-
%>
2、 原因分析:
此时,sdf对象从创建到销毁都位于一个方法中,相当于一个局部变量,不是一个共享资源,因此则没有线程不安全的问题。
3、 解决方法或过程:
1) 如果对象是immutable,则是线程安全的,例如:String,可以放心使用。
2) 如果对象是线程安全的,则放心使用
3) 有条件线程安全,对于Vector和Hashtable一般情况下是线程安全的,但是对于某些特殊情况,需要通过额外的synchronized保证线程安全。
4) 使用synchronized关键字;
对于上例中可以改写jsp代码,在sdf上进行同步,而不需要每次创建一个新的对象来保证线程安全,代码如下:
- <%
- synchronized(C1.sdf){
- Java.util.Date date = C1.sdf.parse(“2003-4-15”);
- }
-
%>
这种写法是在一个对象级别上进行同步,也就是说任何时候,对于这个对象,最多只能有一个线程在执行同步方法。
另外一种写法是在Class级别上进行同步,写法如下:
- public class C1 {
- public static java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd");
- public void method(){
- synchronized(C1.class){
- //synchronized code
- }
- }
-
}
这种写法表示无论C1有多少个实例,在任何一个时间点,最多只能有一个线程和一个实例进入同步块中。这种同步会比较大的影响性能。
5) 有些对象不能在多线程间共享,则只能在方法内部使用,或者只在一个线程内部使用。
synchronized详解
Java对多线程的支持与同步机制深受大家的喜爱,似乎看起来使用了synchronized关键字就可以轻松地解决多线程共享数据同步问题。到底如何?――还得对synchronized关键字的作用进行深入了解才可定论。
总的说来,synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。如果再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。
在进一步阐述之前,我们需要明确几点:
A.无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。
B.每个对象只有一个锁(lock)与之相关联。
C.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
接着来讨论synchronized
用到不同地方对代码产生的影响:
假设P1、P2是同一个类的不同对象,这个类中定义了以下几种情况的同步块或同步方法,P1、P2就都可以调用它们。
1. 把synchronized当作函数修饰符时,示例代码如下:
Public synchronized void methodAAA()
{
//….
}
这也就是同步方法,那这时synchronized锁定的是哪个对象呢?它锁定的是调用这个同步方法对象。也就是说,当一个对象P1在不同的线程中执行这个同步方法时,它们之间会形成互斥,达到同步的效果。但是这个对象所属的Class所产生的另一对象P2却可以任意调用这个被加了synchronized关键字的方法。
上边的示例代码等同于如下代码:
public void methodAAA()
{
synchronized (this) // (1)
{
//…..
}
}
(1)处的this指的是什么呢?它指的就是调用这个方法的对象,如P1。可见同步方法实质是将synchronized作用于object reference。――那个拿到了P1对象锁的线程,才可以调用P1的同步方法,而对P2而言,P1这个锁与它毫不相干,程序也可能在这种情形下摆脱同步机制的控制,造成数据混乱:(
2.同步块,示例代码如下:
public void method3(SomeObject so)
{
synchronized(so)
{
//…..
}
}
这时,锁就是so这个对象,谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时,就可以这样写程序,但当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的instance变量(它得是一个对象)来充当锁:
class Foo implements Runnable
{
private byte[] lock = new byte[0]; // 特殊的instance变量
Public void methodA()
{
synchronized(lock) { //… }
}
//…..
}
注:零长度的byte数组对象创建起来将比任何对象都经济――查看编译后的字节码:生成零长度的byte[]对象只需3条操作码,而Object lock = new Object()则需要7行操作码。
3.将synchronized作用于static 函数,示例代码如下:
Class Foo
{
public synchronized static void methodAAA() // 同步的static 函数
{
//….
}
public void methodBBB()
{
synchronized(Foo.class) // class literal(类名称字面常量)
}
}
代码中的methodBBB()方法是把class literal作为锁的情况,它和同步的static函数产生的效果是一样的,取得的锁很特别,是当前调用这个方法的对象所属的类(Class,而不再是由这个Class产生的某个具体对象了)。
记得在《Effective Java》一书中看到过将 Foo.class和 P1.getClass()用于作同步锁还不一样,不能用P1.getClass()来达到锁这个Class的目的。P1指的是由Foo类产生的对象。
可以推断:如果一个类中定义了一个synchronized的static函数A,也定义了一个synchronized 的instance函数B,那么这个类的同一对象Obj在多线程中分别访问A和B两个方法时,不会构成同步,因为它们的锁都不一样。A方法的锁是Obj这个对象,而B的锁是Obj所属的那个Class。
小结如下:
搞清楚synchronized锁定的是哪个对象,就能帮助我们设计更安全的多线程程序。
还有一些技巧可以让我们对共享资源的同步访问更加安全:
1. 定义private 的instance变量+它的 get方法,而不要定义public/protected的instance变量。如果将变量定义为public,对象在外界可以绕过同步方法的控制而直接取得它,并改动它。这也是JavaBean的标准实现方式之一。
2. 如果instance变量是一个对象,如数组或ArrayList什么的,那上述方法仍然不安全,因为当外界对象通过get方法拿到这个instance对象的引用后,又将其指向另一个对象,那么这个private变量也就变了,岂不是很危险。 这个时候就需要将get方法也加上synchronized同步,并且,只返回这个private对象的clone()――这样,调用端得到的就是对象副本的引用了。
分享到:
相关推荐
总的来说,理解和掌握Java线程的创建、状态管理、同步机制和线程安全是进行多线程编程的基础,这对于开发高效、稳定的并发程序至关重要。在实际编程中,应充分利用Java提供的工具和机制,避免潜在的并发问题,提升...
"多线程的批量线程同步解决方案"这个标题暗示我们探讨的是如何在多线程环境下有效地管理和同步多个任务,确保数据一致性与程序正确性。下面将详细阐述相关知识点。 一、多线程基础 多线程是指在一个进程中同时执行...
Java线程安全是多线程编程中的一个关键概念,它涉及到多个线程访问共享资源时可能出现的问题。在Java中,线程安全问题通常与并发、内存模型和可见性有关。Java内存模型(JMM)定义了如何在多线程环境下共享数据的...
如果同步失败,可能需要回滚主数据库的事务,或者标记异常并尝试在后续同步周期中再次处理。 5. **性能优化**: 为提高同步效率,可以使用批量操作减少网络传输次数,或者使用数据库的binlog(二进制日志)来获取...
Java线程(二):线程同步synchronized和volatile 详细讲解Java 同步的原理技术资料
本文将深入探讨Java中的多线程并发访问解决方案,主要围绕以下几个核心知识点进行阐述: 1. **线程同步机制**: - **synchronized关键字**:Java中的synchronized提供了一种内置锁机制,它可以保证同一时间只有一...
Java多线程-线程的安全问题与线程的同步机制介绍 在 Java 多线程编程中,线程安全问题是非常重要的一个话题。当多个线程访问同一个资源时,如果只有读操作那么不会出现线程安全问题,但是如果多个线程对资源进行读...
总结来说,Java中的同步代码块是一种有效的解决线程安全问题的手段,通过限制对共享资源的并发访问,可以保证数据的一致性和线程的安全性。然而,过度使用同步可能会降低程序的性能,因此需要合理设计同步范围,确保...
Java 线程同步控制机制 线程同步是 Java 编程中的一种机制,用于控制多个线程之间的资源访问顺序,以避免线程之间的冲突和数据不一致。线程同步的目的就是避免线程“同步”执行,即让多个线程之间排队操作共享资源...
在Java中,多线程是一种非常重要的编程概念,...这些面试题涵盖了Java多线程编程的基础知识、同步机制、线程间通信以及并发集合类等多个方面。在准备面试时,对这些问题进行深入理解和准备,能够有效提升面试的成功率。
在Java编程中,线程同步和互斥是多线程编程中的重要概念,它们用于解决多个线程同时访问共享资源时可能出现的问题。本项目通过一个生产者消费者问题的实例,展示了如何在Java中实现线程间的同步与互斥。 生产者消费...
"Java多线程同步.pdf" Java多线程同步是指在Java语言中,如何使用synchronized关键字和其他同步机制来确保多线程程序的正确执行。在Java语言中,synchronized关键字用于对方法或者代码块进行同步,但是仅仅使用...
本文主要研究了基于Java多线程同步的安全性问题,讨论了Java多线程同步机制的实现方法和安全性问题的解决方法。文章首先介绍了Java多线程同步的必要性和重要性,然后讨论了Java多线程同步机制的实现方法,包括使用...
总之,Java的同步方法是一种有效的解决线程安全问题的手段,它可以确保共享资源在多线程环境中的正确访问和更新。但是,过度使用同步可能会导致性能下降,因此在设计多线程程序时,需要根据具体需求和性能考虑来选择...
java线程同步java线程同步java线程同步
java多线程同步互斥访问实例,对于初学者或是温故而知新的同道中人都是一个很好的学习资料
电子书相关:包含4个有关JAVA线程的电子书(几乎涵盖全部有关线程的书籍) OReilly.Java.Threads.3rd.Edition.Sep.2004.eBook-DDU Java Thread Programming (Sams) java线程第二版中英文 java线程第二版中英文 ...
Java多线程同步是Java编程中关键的并发概念,它涉及到如何在多个线程访问共享资源时保持数据的一致性和完整性。`java.util.concurrent`包是Java提供的一个强大的并发工具库,它为开发者提供了多种线程安全的工具,...
在Java中,`volatile`关键字也可以用于线程同步,但它的作用比`synchronized`轻量级,主要用于解决单个变量在多线程环境中的可见性问题,而不是防止数据竞争。 总结一下,Java线程同步的关键点: 1. **线程同步是...