线程的同步

                        线程的同步
线程的特点
   计算机中一个程序可以启动多个进程,一个进程又可以启动多个线程。进程之间在内存中是相互独立的,它们不能彼此进行访问,已不能修改彼此的数据,那么进程之间怎样做到共享数据呢,一般有两种方法,第一种是通过网络,即进程A把数据发到服务器,然后服务器再将这些数据发给进程B,同样进程B也可以把数据发到服务器,然后服务器再将这些数据发给进程A;第二种方式是进程A把数据存到本地的硬盘文件中,然后进程B再到硬盘里去读这个文件,同样进程B也可以把数据存到本地的硬盘文件中,然后进程A再到硬盘里去读这个文件。但是,进程启动的多个线程中间是可以共享内存里的数据的,也可以修改这些数据。还有进程之间可以并发执行,即同步执行。
线程同步的好处
   当一个计算很复杂或是很庞大的时候,我们可以把它分为若干个比较简单的计算模块,然后再把这若干个计算模块交给若干个线程去处理,最后把这些返回的计算结果统计整理。比如我们有统计计算机中所有文件的个数。我们就可以启动多个线程去统计每一个盘符里面的文件个数,然后再把它们全部加起来,就可以得到文件的总个数。
其代码如下:

public class Filecount extends Thread{ 
        private int num;//用来保存文件个数的属性 
        private String name;//文件的路径 
        private boolean bl=false;//用来判断文件是否统计完的一个属性 
        /** 
    * 重载构造方法,得到要统计的文件名 
    */ 
        public Filecount(String name){ 
        this.name=name; 
        } 
        //获得统计后的文件个数 
        public int getNum(){ 
        return num; 
        } 
        //一个或得统计状态的方法,true代表已经统计完了,false代表没有统计完 
        public boolean isFinish(){ 
        return bl; 
        } 
      //重写线程的run方法 
    public void run(){ 
    count(name); 
        bl=true; 
        
    } 
    /** 
    * 统计文件的方法 
    */ 
    public  void count(String name){ 
    // 根据文件路径创建文件对象 
       java.io.File file=new java.io.File(name); 
         // 如果表示的文件不存在 
    if(!file.exists()){ 
    return; 
    } 
    // 将该文件夹下的所有文件装在一个文件数组中 
    java.io.File[] myfs=file.listFiles(); 
    if(myfs==null){ 
    return; 
    } 
      // 遍历数组 
      for(int i=0;i<myfs.length;i++){ 
    java.io.File fs=myfs[i]; 
    // 得到文件的地址 
    String s=fs.getAbsolutePath(); 
    // 如果是一个标准文件 
    if(fs.isFile()){ 
    //文件加一 
    num++; 
    
    //如果是文件夹 
    }else if(fs.isDirectory()){ 
    //递归调用 
    try{//进行适当的休眠以免cpu被过度占用 
    Thread.sleep(20); 
    }catch(Exception ef){ 
        ef.printStackTrace(); 
    } 
        this.count(s); 
    } 
       } 
    } 
} 

   测试的主函数

public class Counter extends Thread{ 
      private int filenum=0;//用来保存文件个数 

public static void main(String[] args) { 
Counter count=new Counter();//创建一个统计所有文件个数的对象 
        count.start();       //启动线程去统计所有线程返回的结果 
} 
//重载run方法 
public void run(){ 
        Filecount E_counter=new Filecount("E:\\");//创建一个统计E盘的对象 
          E_counter.start(); 
        Filecount F_counter=new Filecount("F:\\");//创建一个统计F盘的对象 
F_counter.start(); 
while(true){ 
if(E_counter.isFinish()&&F_counter.isFinish()){//不断的判断线程是否已经把所有文件统计完了 
break;//跳出循环 
  } 
try{//进行适当的休眠 
       Thread.sleep(200); 
  }catch(Exception ex){ 
ex.printStackTrace(); 
} 
} 
filenum=E_counter.getNum()+F_counter.getNum(); 
System.out.println("标准文件的总个数为:"+filenum); 
} 
} 

 
如果要进一步的提过效率,我们可以通过对文件进行判断,若是一个很大的文件,我们可以在启动线程去统计。
通过将任务进行分配,有时是可以提过效率,但是并不是把任务分配给线程,就一定能提过效率。像上面统计文件个数的情况,如果我只是简单的分配任务,其实并不能提高效率。而且像上面的情况是,线程什么时候运行结束了,并不知道。所以我们得优化线程的工作机制。

同步线程的影响
  假设一下,如果有两个线程同时对一个变量进行操作,会有什么情况。因为同步线程之间的执行并不是同时的,也不一定是按照先后的顺序执行的,这取决与CPU和操作系统等因素。所以当两个或以上的线程同时操作同一块内存时,就有可能会产生影响。这种影响可能会导致一些不可预见的结果。
线程模型的优化
生产/消费者模型的应用,在统计每个盘的文件的时候,因为我们不知道哪个盘的统计已经完成了,所以我们得不停的去询问,也就是不断的去判断它们是否已经全部统计完了,这样做显然很不合理,那么我们能不能改进一下呢,当然是可以的。看到生产和消费是不是有些不理解,凭常识我们就能知道必须先生产出东西来,我才能进行消费,所以只要当我们知道生产这把东西生产出来就可以去买了。在“产品”
没有生产出来之前,我们就必须得在家里等到,知道有人通知我们产品已经生产出来了,我们才去买。这样在中生产/消费者模型有别转会成为等待/通知(wait()/notify())模型了。
下面是实现这种机制的具体代码

public class Filecount extends Thread{ 
        private int num;//用来保存文件个数的属性 
        private String name;//文件的路径 
        private Counter count; 
        /** 
    * 重载构造方法,得到要统计的文件名 
    */ 
        public Filecount(String name,Counter count){ 
        this.name=name; 
        this.count=count; 
        } 
        //获得统计后的文件个数 
        public int getNum(){ 
        return num; 
        } 
       
      //重写线程的run方法 
    public void run(){ 
count(name);//统计文件个数的方法 
    synchronized(count){//将counter对象锁住    
        count.notify();//   统计完该盘的文件个数后,就通知它 
    } 
    } 
    /** 
    * 统计文件的方法 
    */ 
    public  void count(String name){//统计文件个数的方法 
   public  void count(String name){
    		// 根据文件路径创建文件对象
       	 java.io.File file=new java.io.File(name); 
         // 如果表示的文件不存在
    	 if(!file.exists()){		
    		 return;
    	 }
    	 // 将该文件夹下的所有文件装在一个文件数组中
    	 java.io.File[] myfs=file.listFiles();
    	 if(myfs==null){
    		 return;
    	 }
    	  // 遍历数组
    	  for(int i=0;i<myfs.length;i++){
    		 java.io.File fs=myfs[i];
    		// 得到文件的地址
    		 String s=fs.getAbsolutePath();
    		// 如果是一个标准文件
    		 if(fs.isFile()){
    			 //文件加一
    			 num++;
    					 
    		 //如果是文件夹
    		 }else if(fs.isDirectory()){
    			//递归调用
    			 try{//进行适当的休眠以免cpu被过度占用
    				 Thread.sleep(20);
    			 }catch(Exception ef){
    				 ef.printStackTrace();
    			 }
    			 this.count(s);
    		 }
    	   } 	
    	}} 

 

public class Counter extends Thread{ 
      private int filenum=0;//用来保存文件个数 

public static void main(String[] args) { 
Counter count=new Counter();//创建一个统计所有文件个数的对象 
        count.start();       //启动线程去统计所有线程返回的结果 
} 
//重载run方法 
public void run(){ 

Filecount E_counter=new Filecount("E:\\",this);//创建一个统计E盘的对象 
E_counter.start(); 
Filecount F_counter=new Filecount("F:\\",this);//创建一个统计F盘的对象 
F_counter.start(); 
synchronized(this){//将当前这个对象锁住 
try { 
  this.wait();//等待通知第一个统计者的通知 
  this.wait();//等待通知第二个统计者的通知 
   } catch (InterruptedException e) { 

e.printStackTrace(); 
   } 
} 
filenum=E_counter.getNum()+F_counter.getNum(); 
System.out.println("标准文件的总个数为:"+filenum); 
} 
} 

 
里面使用的wait()有阻塞的作用,用就是说如果等不到通知notify(),wait()就不会执行下去,就可阻塞在wait()里。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值