`
神绮_H_亚里亚
  • 浏览: 10445 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

线程(下)

阅读更多

    Java 应用程序中的多线程可以共享资源,例如文件、数据库、内存等。当线程以并发模式访问共享数据时,共享数据可能会发生冲突。Java引入线程同步的概念,以实现共享数据的一致性。线程同步机制让多个线程有序的访问共享资源,而不是同时操作共享资源。 

1  . 同步概念 

    在线程异步模式的情况下,同一时刻有一个线程在修改共享数据,另一个线程在读取共享数据,当修改共享数据的线程没有处理完毕,读取数据的线程肯定会得到错误的结果。如果采用多线程的同步控制机制,当处理共享数据的线程完成处理数据之后,读取线程读取数据。 
     
通过分析多线程出售火车票的例子,可以更好得理解线程同步的概念。线程 Thread1 和线程 Thread2 都可以出售火车票,但是这个过程中会出现数据与时间信息不一致的情况。线程 Thread1 查询数据库,发现某张火车票 T 可以出售,所以准备出售此票;此时系统切换到线程Thread2执行,它在数据库中查询存票,发现上面的火车票T可以出售,所以线程Thread2将这张火车票 T 售出;当系统再次切换到线程 Thread1 执行时,它又卖出同样的票 T。这是一个典型的由于数据不同步而导致的错误。 
     
下面举一个线程异步模式访问数据的例子。 

//文件:程序ThreadNoSynchronized.java   描述:多线程不同步的原因   
class ShareData {  
    public static String szData = ""; // 声明,并初始化字符串数据域,作为共享数据  
  
}  
class ThreadDemo extends Thread {  
    private ShareData oShare; // 声明,并初始化ShareData 数据域  
    ThreadDemo() {  
    } // 声明,并实现ThreadDemo 构造方法  
  
    // 声明,并实现ThreadDemo 带参数的构造方法  
    ThreadDemo(String szName, ShareData oShare) {  
        super(szName); // 调用父类的构造方法  
        this.oShare = oShare; // 初始化oShare域  
    }  
    public void run() {  
        for (int i = 0; i < 5; i++) {  
            if (this.getName().equals("Thread1")) {  
                oShare.szData = "这是第 1 个线程";  
                // 为了演示产生的问题,这里设置一次睡眠  
                try {  
                    Thread.sleep((int) Math.random() * 100); // 休眠  
                } catch (InterruptedException e) { // 捕获异常  
                }  
                System.out.println(this.getName() + ":" + oShare.szData); // 输出字符串信息  
            } else if (this.getName().equals("Thread2")) {  
                oShare.szData = "这是第 2 个线程";  
                // 为了演示产生的问题,这里设置一次睡眠  
                try {  
                    Thread.sleep((int) Math.random() * 100); // 线程休眠  
                } catch (InterruptedException e) // 捕获异常  
                {  
                }  
                System.out.println(this.getName() + ":" + oShare.szData); // 输出字符串信息  
            }  
        }  
    }  
}  
  
public class ThreadNoSynchronized {  
    public static void main(String argv[]) {  
        ShareData oShare = new ShareData(); // 创建,初始化ShareData对象oShare  
        ThreadDemo th1 = new ThreadDemo("Thread1", oShare); // 创建线程th1  
        ThreadDemo th2 = new ThreadDemo("Thread2", oShare); // 创建线程th2  
        th1.start(); // 启动线程th1  
        th2.start(); // 启动线程th2  
    }  
}  

 Thread1:这是第 2 个线程

Thread1:这是第 1 个线程
Thread1:
这是第 1 个线程
Thread1:
这是第 1 个线程
Thread1:
这是第 1 个线程
Thread2:
这是第 2 个线程
Thread2:
这是第 2 个线程
Thread2:
这是第 2 个线程
Thread2:
这是第 2 个线程
Thread2:
这是第 2 个线程

  程序中预想的结果是:“Thead1:这是第1 个线程“Thead2:这是第2 个线程,但是线程对数据的异步操作导致运行结果出现了差错。  上面程序是由于线程不同步而导致错误。为了解决此类问题,Java 提供了机制实现线程的同步。 

        锁机制的原理是每个线程进入共享代码之前获得锁,否则不能进入共享代码区,并且在退出共享代码之前释放该锁,这样就解决了多个线程竞争共享代码的情况,达到线程同步的目的。Java中锁机制的实现方法是共享代码之前加入 synchronized 关键字。 

        在一个类中,用关键字 synchonized 声明的方法为同步方法。Java 有一个专门负责管理线程对象中同步方法访问的工具——同步模型监视器,它的原理是为每个具有同步代码的对象准备惟一的一把。当多个线程访问对象时,只有取得锁的线程才能进入同步方法,其他访问共享对象的线程停留在对象中等待,如果获得锁的线程调用wait方法放弃锁,那么其他等待获得锁的线程将有机会获得锁。当某一个等待线程取得锁,它将执行同步方法,而其他没有取得锁的线程仍然继续等待获得锁。 
       Java
程序中线程之间通过消息实现相互通信,wait()notify() notifyAll()方法可完成线程间的消息传递。例如,一个对象包含一个 synchonized 同步方法,同一时刻只能有一个获得锁的线程访问该对象中的同步方法,其他线程被阻塞在对象中等待获得锁。当线程调用 wait()方法可使该线程进入阻塞状态,其他线程调用notify() notifyAll()方法可以唤醒该线程。 

2 .同步格式 

    当把一语句块声明为 synchornized,在同一时间,它的访问线程之一才能执行该语句块。

 

  

 //方法同步:用关键字 synchonized 可将方法声明为同步	
class 类名{   
	     public synchonized 类型名称 方法名称(){   
	           ......   
	     }   
	}   
 // 语句块同步: 对于同步块,synchornized 获取的是参数中的对象锁。 
	synchornized(obj)   
	{    
	  //………………….    
	}   

   当线程执行到这里的同步块时,它必须获取 obj 这个对象的锁才能执行同步块;否则线程只能等待获得锁。必须注意的是obj对象的作用范围不同,控制情况不尽相同。示例如下。  

	public void method()   
	{    
	  Object obj= new Object(); //创建局部Object类型对象obj   
	  synchornized(obj)   //同步块   
	  {   
	      //……………..    
	  }    
	}   

    上面的代码创建了一个局部对象obj。由于每一个线程执行到 Object obj = new Object()时都会产生一个 obj 对象,每一个线程都可以获得创建的新的 obj对象的锁,不会相互影响,因此这段程序不会起到同步作用。

     3)同步类的属性:如果同步的是类的属性,情况就不同了。同步类的成员变量的一般格式如下。 

class method   
{    
    Object o = new Object();  //创建Object类型的成员变量o   
public void test()   
{    
synchornized(o)  //同步块   
{    
            //………………………   
        }    
	    }    
	}   

  当两个并发线程访问同一个对象的 synchornized(o)同步代码块时,一段时间内只能有一个线程运行。另外的线程必须等到当前线程执行完同步代码块释放锁之后,获得锁的线程将执行同步代码块。

     有时可以通过下面的格式声明同步块。 

    public void method()   
    {    
    synchornized(this)  //同步块   
    {    
        //………………………   
        }    
    }   

  当有一个线程访问某个对象的 synchornized(this)同步代码块时,另外一个线程必须等待该线程执行完此代码块,其他线程可以访问该对象中的非 synchornized(this)同步代码。如果类中包含多个 synchornized(this)同步代码块,如果同步线程有一个访问其中一个代码块,则其他线程不能访问该对象的所有 synchornized(this)同步代码块。对于下面形式的同步块而言,调用 ClassName 对象实例的并行线程中只有一个线程能够访问该对象。 

	synchornized(ClassName.class)   
	{    
	    //…………………….   
	}   

 

 

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

    host多线程下OpenCL平台等单例(最终版本)

    host端多个线程,OpenCL创建平台设备program和context及读kernel创建公共buffer部分单例,不加锁版本,因为为每个线程创建了结果buffers而不是共用一个结果buffer,所以不用加锁

    多线程下的websocket实时通信

    Fleck.dll支持websocket引自博客文章多线程下的websocket实时通信,具体使用方式请看文章多线程下的websocket实时通信,包括具体的服务器端跟客户端编码。

    使用QT5.9开发海康威视相机,多线程下使用QLabel实时显示相机捕获的图像

    在本文中,我们将深入探讨如何使用QT5.9框架与海康威视的相机设备进行交互,以及在多线程环境中实现QLabel组件实时显示相机捕获的图像。海康威视是全球知名的安防监控设备制造商,其产品广泛应用于各种监控场景。而...

    C++ 多线程和多线程下的单例模式

    本资源描述了C++11 中多线程的创建,C++11中std命名空间中将boost库中的Thread加入,boost多线程从准标准变为标准,其中还介绍了C++ 多线程下的单例模式的使用,本文档为txt文档

    多线程下的CSocket

    网上很多人对于CSocket不是很了解,认为CSocket不支持多线程,没什么用,其实CSocket是支持多线程的,只是他们使用的方法不对。在此,我写了一个简单的示例,有兴趣的朋友可以看看如何在多线程中使用CSocket。

    单线程下ThreadX线程调度问题

    在单线程环境下,ThreadX线程调度的问题主要集中在如何优化系统性能、确保任务的实时性和避免资源浪费。本篇文章将深入探讨ThreadX线程调度机制以及在单线程环境下的工作原理。 首先,理解ThreadX的基本概念至关...

    PB多线程实现

    1. **线程安全**:确保共享数据在多线程环境下正确访问,通常需要使用锁(如Monitor或Mutex)、信号量(Semaphore)或原子操作来实现。 2. **线程间通信**:线程间的同步和通信至关重要,可以使用事件(Event)、...

    C#队列Queue多线程用法实例

    队列在多线程环境下常常用于任务调度、消息传递等场景,因为它们能有效地管理和同步数据访问。本实例将详细讲解如何在多线程中使用C#的Queue类。 首先,我们创建一个队列实例,通过`new Queue()`来指定存储的数据...

    易语言多线程传递文本参数两种方法

    需要注意的是,由于多线程环境下可能存在数据竞争的问题,使用全局变量或共享内存时,需要采取适当的同步措施,如使用锁或信号量,以避免数据的不一致。 这两种方法各有优缺点。第一种方法简单直接,但参数只能在...

    Java Socket/ServerSocket 多线程下聊天室系统

    在聊天室系统中,每个连接的客户端都会创建一个新的线程,以便服务器可以同时处理来自不同客户端的请求,避免了单线程模型下的阻塞问题。例如,当一个客户端发送消息时,其他客户端可以同时接收和发送信息,保持系统...

    QT中sqlite多线程操作4个注意问题

    多线程下的各个线程或定时器数据库驱动加载需独立进行 在多线程环境中,不同线程间共享资源会导致各种难以预料的问题。对于SQLite数据库而言,如果多个线程试图同时访问同一个数据库实例,则很容易出现死锁或其他...

    Delphi多线程Demo

    此外,还可以使用TThread.Queue方法,它会将一个方法放到线程的消息队列中,当线程下一次检查队列时执行该方法,但不会切换到主线程上下文。 除了Synchronize和Queue,Delphi还提供了TThread.OnTerminate事件,当...

    COM多线程访问演示

    总结来说,"COM多线程访问演示"是一个深入学习COM组件多线程编程的资源,它将帮助你理解如何在多线程环境下正确地创建、管理和同步COM对象,提升组件的并发性能和系统稳定性。通过研究这个压缩包中的内容,你将能够...

    powerbuilder多线程示例

    6. **异常处理**:在多线程环境下,异常处理显得尤为重要。确保每个线程都有适当的异常处理代码,以防止未捕获的异常导致整个进程崩溃。 7. **性能优化**:尽管多线程能提高程序性能,但过多的线程会消耗大量系统...

    C#多线程实现等待窗体

    在C#中,我们可以通过`System.Threading`命名空间下的`Thread`类或者`Task`类来创建新线程。对于UI更新,由于跨线程访问控件可能导致异常,我们需要使用`Control.Invoke`或`Control.BeginInvoke`方法来确保在正确的...

    C#实现多线程操作控件

    在VS2008环境下,C#提供了丰富的多线程支持,使开发者可以方便地创建和管理线程。 标题“C#实现多线程操作控件”指的是在C#应用程序中,如何在一个单独的线程(非主线程)上执行对UI控件的操作。通常,Windows ...

    详解Python多线程下的list

    那么如果我们试着在多线程下操作list 会有问题吗? 多线程下的 list 安全 or 不安全? 不安全! 通常我们说的线程安全是指针对某个数据结构的所有操作都是线程安全,在这种定义下,Python 常用的数据结构 list,dict,...

    VC++线程开关

    总的来说,理解和掌握VC++中的线程控制技术,尤其是如何在特定循环条件下安全地开关线程,对于开发高效且健壮的多线程应用程序至关重要。通过合理的线程设计和同步策略,开发者可以构建出更加灵活和响应迅速的应用。

    Win32 多线程程序设计(pdf)

    《Win32多线程程序设计》是一本深入探讨Windows操作系统环境下如何开发多线程应用程序的专业书籍。在当今计算机系统中,多线程已经成为提升软件性能、实现并发处理的关键技术。Win32 API提供了丰富的接口支持多线程...

Global site tag (gtag.js) - Google Analytics