线程(下)_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > 线程(下)

线程(下)

 2017/6/28 5:59:48  神绮_H_亚里亚  程序员俱乐部  我要评论(0)
  • 摘要:Java应用程序中的多线程可以共享资源,例如文件、数据库、内存等。当线程以并发模式访问共享数据时,共享数据可能会发生冲突。Java引入线程同步的概念,以实现共享数据的一致性。线程同步机制让多个线程有序的访问共享资源,而不是同时操作共享资源。1.同步概念在线程异步模式的情况下,同一时刻有一个线程在修改共享数据,另一个线程在读取共享数据,当修改共享数据的线程没有处理完毕,读取数据的线程肯定会得到错误的结果。如果采用多线程的同步控制机制,当处理共享数据的线程完成处理数据之后,读取线程读取数据
  • 标签:线程

class="MsoNormal">? ? 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)   
	{    
	    //…………………….   
	}   

?

?

?

?

?

?

?

?

?

?

发表评论
用户名: 匿名