`
xyheqhd888
  • 浏览: 409241 次
  • 性别: Icon_minigender_1
  • 来自: 秦皇岛
社区版块
存档分类
最新评论

Java线程之同步化(Synchronized)主题

阅读更多

1.  如果一个对象所持有的数据可以被多线程同时共享存取,必须考虑到数据同步的问题。所谓数据同步指的是两份数据的整体性和一致性。数据在多线程下共享时容易由于同时多个线程可能更新同一个对象的信息,而造成对象数据的不同步,因为数据的不同步可能引发的错误通常不易察觉,而且可能是在程序执行了几千几万次之后,才会发生错误。这通常会发生在产品已经上线之后,甚至是程序已经执行了几年之后。

2. 举个简单的例子,设计了一个PersonalInfo类:   

package ysu.hxy;

public class PersonalInfo 
{
	private String name;
	private String id;
	private int count;

	public PersonalInfo()
	{
		name = "nobody";
		id = "N/A";
	}

	public void setNameAndID(String name,String id)
	{
		this.name = name;
		this.id = id;
		if(!checkNameAndIDEqual())
		{
             System.out.println(count + ") illegal name or ID...");
		}
		count ++;
	}

	private boolean checkNameAndIDEqual(){
		return (name.charAt(0) == id.charAt(0)) ? true:false;
	}
}

 单就这个类本身而言,它并没有任何的错误,但如果它被用于多线程的程序中,而且同一个对象被多个线程存取时,就会有可能发生错误。下面是一个简单的测试程序,看看PersonalInfo类在多线程共享数据下会发生什么问题。

package ysu.hxy;

public class PersonalInfoTest 
{
	public static void main(String[] args) 
	{
		final PersonalInfo person = new PersonalInfo();

		//假设会能两个线程可能更新person对象 
		Thread thread1 = new Thread(new Runnable() {
			public void run() {
				while(true){
					person.setNameAndID("Justin Lin","J.L");
				}
			}
		});

        Thread thread2 = new Thread(new Runnable() {
			public void run() {
				while(true){
					person.setNameAndID("Shang Hwang Lin","S.H");
				}
			}
		});

		System.out.println();

		thread1.start();
		thread2.start();
	}
}

 

执行结果:

D:\hxy>java ysu.hxy.PersonalInfoTest
开始测试...
23466451) illegal name or ID...
78044494) illegal name or ID...
101630476) illegal name or ID...
106496643) illegal name or ID...
145330181) illegal name or ID...
169674022) illegal name or ID...
174072203) illegal name or ID...
214717201) illegal name or ID...
219668799) illegal name or ID...
240921750) illegal name or ID...
265875722) illegal name or ID...
270920923) illegal name or ID...
281256783) illegal name or ID...

这个程序出现了错误,在23466451次的setNameAndID()执行时就开始了。如果程序完成并开始应用于实际场合之后,这个时间点可能是几个月甚至是几年之后。问题出在这里:

public void setNameAndID(String name,String id)
	{
		this.name = name;
		this.id = id;
		if(!checkNameAndIDEqual())
		{
             System.out.println(count + ") illegal name or ID...");
		}
		count ++;
	}

      虽然传递给setNameAndID()的变量并没有问题,在某个时间点时,thread1设定了Justin Lin、J.L给name和id,在进行if测试的前一刻,thread2可能此时刚好调用setNameAndID("Shang Hwang","S.H")。在name被设定为Shang HWang时,checkNameAndIDEqual()开始执行,此时name等于Shang HWang,而id还是J.L。所以,checkNameAndIDEqual()就会返回false,结果就显示了错误信息。

       必须同步数据对对象的更新,方法在有一个线程正在设定person对象的数据时,不可以被另一个线程同时进行设定。可以使用synchronized关键词来进行这个动作。

public synchronized void setNameAndID(String name,String id)
	{
		this.name = name;
		this.id = id;
		if(!checkNameAndIDEqual())
		{
             System.out.println(count + ") illegal name or ID...");
		}
		count ++;
	}

 这是synchronized关键词的一个使用方式,用于方法上让方法的范围内都成为被同步化区域。被同步化区域在有一个线程占据时就像一个禁区,不允许其他线程进入。由于同时间只能有一个线程在被同步化区域,所以更新共享数据时,就像单线程程序在更新数据一样,以保证对象中的数据会与给定的数据同步。

  sychronized的设定不只可用于方法上,也可以用于限定某个程序区块上被同步化区域。例如: 

public void setNameAndID(String name,String id)
  { //同步某个程序区块
       synchronized(this)
   {
       this.name = name;
       this.id = id;
       if(!checkNameAndIDEqual())
          {
               System.out.println(count+") illegal name or ID...");
          }
   }
}

   这个程序片段的意思是,在线程执行到synchronized设定的被同步化区块时锁定当前对象,这样就没有其他线程可以来执行这个被同步化区块。这个方式可以应用于您不想锁定整个方法区块,而只是想在更新共享数据时再确保对象与数据的同步化。由于只锁定方法中的某个区块,在执行完区块后即释放对对象的锁定,以便让其他线程能有机会对对象进行操作,相对于锁定整个方法区块效率较高。

   也可以标示某个对象要求同步化。例如在多线程中存取同一个ArrayList对象时,由于ArrayList并没有实现数据存取时的同步化,所以当它使用多线程环境时,必须注意多个线程存取同一个ArrayList时,有可能发生两个以上的线程将数据存入ArrayList的同一个位置,造成数据的相互覆盖。为了确保数据存入时的正确性,可以在存取ArrayList对象时要求同步化。例如:

//arraylist参考至一个ArrayList的一个实例
synchronized(arraylist)
{
     arrayList.add(new SomeClass());
}

 同步化确保数据的同步,但所牺牲的就是在于一个线程占据同步化区块,而其他线程等待它释放区块执行权时的延迟。这在线程少时可能看不出来,但在线程多的环境中必然造成一定的效率问题(例如大型网站的多人联机时)。   

 

分享到:
评论

相关推荐

    详细解读java同步之synchronized解析

    Java中的`synchronized`关键字是实现多线程同步的重要机制,它确保了在并发环境中对共享资源的访问是线程安全的。以下是对`synchronized`的详细解读: ### 1. synchronized的特性 - **互斥性**:当一个线程进入一...

    java线程同步实例

    根据提供的信息,我们可以深入探讨Java线程同步以及代码示例中的关键知识点。 ### Java线程同步实例:哲学家就餐问题 #### 1. 哲学家就餐问题简介 哲学家就餐问题是多线程编程中一个经典的同步问题。该问题描述为...

    java Thread & synchronized & concurrent 线程、同步、并发

    在Java编程语言中,线程(Thread)、同步(synchronized)和并发(Concurrency)是核心概念,对于构建高效、可扩展的应用程序至关重要。线程允许程序同时执行多个任务,而同步是控制多个线程对共享资源的访问,以...

    java线程同步的例子.pdf

    总结一下,Java线程同步通过`synchronized`关键字提供了线程安全的共享资源访问。同步方法和同步代码块是实现同步的两种主要方式,它们都基于监视器(锁)的概念,确保在任何时刻只有一个线程能执行特定的代码段。在...

    Java 模拟线程并发

    除了基本的线程创建,Java还提供了synchronized关键字用于线程同步,防止多个线程同时访问共享资源导致数据不一致。synchronized可以修饰方法或代码块,当一个线程正在执行synchronized代码时,其他线程必须等待。 ...

    JAVA100例之实例64 JAVA线程间通讯

    在"JAVA100例之实例64 JAVA线程间通讯"这个主题中,我们将深入探讨Java中实现线程间通信的几种主要方法。 1. **共享数据**:最直观的线程间通信方式是通过共享内存空间,即共享变量。只要对共享变量的操作是线程...

    java多线程编程总结

    #### 一、Java线程:概念与原理 - **操作系统中线程和进程的概念** 当前的操作系统通常都是多任务操作系统,多线程是一种实现多任务的方式之一。在操作系统层面,进程指的是内存中运行的应用程序,每个进程拥有...

    Java多线程 之 临界区、ThreadLocal.docx

    总结来说,Java中的临界区通过`synchronized`关键字或Lock对象来保证多线程环境下的数据一致性,而ThreadLocal则通过为每个线程提供变量的独立副本,避免了共享资源的并发问题。在实际编程中,开发者需要根据具体...

    Java多线程编程经验

    #### 九、Java线程:线程的同步-同步方法与同步块 同步方法和同步块是实现线程安全的基本手段。同步方法简单易用,而同步块则更加灵活,可以根据需要选择锁定特定的对象。 #### 十、Java线程:并发协作-生产者消费...

    java线程安全测试

    Java线程安全是多线程编程中的一个关键概念,它涉及到多个线程访问共享资源时可能出现的问题。在Java中,线程安全问题通常与并发、内存模型和可见性有关。Java内存模型(JMM)定义了如何在多线程环境下共享数据的...

    java多线程编程之使用Synchronized关键字同步类方法

    `synchronized`关键字提供了线程同步机制,确保在任何时刻只有一个线程能够执行特定的代码块。 在描述中提到的示例中,将`synchronized`关键字添加到`run()`方法前面,可以使该方法成为同步方法。这意味着当一个...

    java 多线程示例

    Java提供了synchronized关键字来实现线程同步,确保同一时刻只有一个线程能执行特定代码块。 5. **死锁** 死锁是两个或多个线程相互等待对方释放资源而造成的僵局。避免死锁的关键在于遵循资源请求的顺序化和避免...

    Java多线程编程总结

    - 锁是实现线程同步的一种机制,主要包括内置锁(`synchronized`)和显式锁(`java.util.concurrent.locks.Lock`)。 - 显式锁提供了更灵活的锁定机制,如可重入锁、读写锁等。 #### 六、Java线程:线程的交互 - ...

    java线程安全总结.doc

    3. **线程安全对象**:对象提供了保证线程安全的方法,如内部同步化或者原子操作。 4. **线程局部变量**:每个线程都有自己的副本,不会造成数据冲突,如`ThreadLocal`类。 ### 三、线程安全策略 1. **同步机制**...

    Java线程详解(ppt)

    总结来说,Java线程是实现并发和提高程序性能的关键,理解并熟练掌握线程的创建、管理以及同步机制对于编写高效、可靠的Java程序至关重要。通过`Thread`类或`Runnable`接口,开发者可以灵活地创建和控制线程,实现...

    Java多线程中使用synchronized说明

    Java中的`synchronized`关键字是用于实现线程同步的关键机制,它的主要目的是确保多个线程在访问共享资源时能保持数据的一致性和完整性,避免出现竞态条件和数据不一致的问题。在Java多线程编程中,`synchronized`有...

    Java线程PDF

    - **定义**: Java线程是Java语言中实现多线程编程的核心概念之一。它允许开发者在一个进程中创建多个独立执行的路径,这些路径可以并发运行,从而提高程序的效率和响应能力。 - **重要性**: Java线程对于构建高性能...

    JAVAJAVA多线程教学演示系统论文

    3. **线程同步与并发控制**:论文会深入讲解JAVA中的线程同步机制,如synchronized关键字、wait()、notify()和notifyAll()方法,以及Lock接口和ReentrantLock类的使用。此外,可能会探讨并发工具类,如Semaphore、...

    java线程入门

    Java线程是多任务编程的重要概念,特别是在Java这种支持并发执行的编程语言中。线程允许程序中的不同部分并行运行,从而提高了程序的效率和响应性。在Java中,线程可以分为两种类型:用户线程(由应用程序创建)和...

Global site tag (gtag.js) - Google Analytics