当前位置:七道奇文章资讯编程技术Java编程
日期:2011-03-22 16:16:00  来源:本站整理

<b>Java若何同享资源</b>[Java编程]

赞助商链接



  本文“<b>Java若何同享资源</b>[Java编程]”是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具体内容:
对一种特别的资源——对象中的内存——Java供应了内建的机制来避免它们的冲突.由于我们普通将数据元素设为从属于private(私有)类,然后只通过办法拜候那些内存,所以只需将一个特定的办法设为synchronized(同步的),便可有效地避免冲突.在任什么时刻刻,只可有一个线程调用特定对象的一个synchronized办法(固然那个线程可以调用多个对象的同步办法).下面列出简单的synchronized办法:
synchronized void f() { /* ... */ }
synchronized void g() { /* ... */ }
每个对象都包含了一把锁(也叫作“监督器”),它自动成为对象的一部份(没必要为此写任何特别的代码).调用任何synchronized办法时,对象就会被锁定,不可再调用那个对象的其他任何synchronized办法,除非第一个办法完成了自己的工作,并解除锁定.在上面的例子中,假如为一个对象调用f(),便不能再为一样的对象调用g(),除非f()完成并解除锁定.因此,一个特定对象的全部synchronized办法都同享着一把锁,并且这把锁能避免多个办法对通用内存同时举行写操作(比方同时有多个线程).
每个类也有自己的一把锁(作为类的Class对象的一部份),所以synchronized static办法可在一个类的范围内被彼此间锁定起来,避免与static数据的接触.
注意假如想保护其他某些资源不被多个线程同时拜候,可以强迫通过synchronized方拜候那些资源.

1. 计数器的同步
装备了这个新关键字后,我们可以采纳的筹划就更机动了:可以只为TwoCounter中的办法简单地利用synchronized关键字.下面这个例子是对前例的改版,此中加入了新的关键字:
//: Sharing2.java
// Using the synchronized keyword to prevent
// multiple access to a particular resource.
import java.awt.*;
import java.awt.event.*;
import java.applet.*;

class TwoCounter2 extends Thread {
  private boolean started = false;
  private TextField 
    t1 = new TextField(5),
    t2 = new TextField(5);
  private Label l = 
    new Label("count1 == count2");
  private int count1 = 0, count2 = 0;
  public TwoCounter2(Container c) {
    Panel p = new Panel();
    p.add(t1);
    p.add(t2);
    p.add(l);
    c.add(p);
  }    
  public void start() {
    if(!started) {
      started = true;
      super.start();
    }
  }
  public synchronized void run() {
    while (true) {
      t1.setText(Integer.toString(count1++));
      t2.setText(Integer.toString(count2++));
      try {
        sleep(500);
      } catch (InterruptedException e){}
    }
  }
  public synchronized void synchTest() {
    Sharing2.incrementAccess();
    if(count1 != count2)
      l.setText("Unsynched");
  }
}

class Watcher2 extends Thread {
  private Sharing2 p;
  public Watcher2(Sharing2 p) { 
    this.p = p;
    start();
  }
  public void run() {
    while(true) {
      for(int i = 0; i < p.s.length; i++)
        p.s[i].synchTest();
      try {
        sleep(500);
      } catch (InterruptedException e){}
    }
  }
}

public class Sharing2 extends Applet {
  TwoCounter2[] s;
  private static int accessCount = 0;
  private static TextField aCount = 
    new TextField("0", 10);
  public static void incrementAccess() {
    accessCount++;
    aCount.setText(Integer.toString(accessCount));
  }
  private Button 
    start = new Button("Start"),
    observer = new Button("Observe");
  private boolean isApplet = true;
  private int numCounters = 0;
  private int numObservers = 0;
  public void init() {
    if(isApplet) {
      numCounters = 
        Integer.parseInt(getParameter("size"));
      numObservers = 
        Integer.parseInt(
          getParameter("observers"));
    }
    s = new TwoCounter2[numCounters];
    for(int i = 0; i < s.length; i++)
      s[i] = new TwoCounter2(this);
    Panel p = new Panel();
    start.addActionListener(new StartL());
    p.add(start);
    observer.addActionListener(new ObserverL());
    p.add(observer);
    p.add(new Label("Access Count"));
    p.add(aCount);
    add(p);
  }
  class StartL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      for(int i = 0; i < s.length; i++)
        s[i].start();
    }
  }
  class ObserverL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      for(int i = 0; i < numObservers; i++)
        new Watcher2(Sharing2.this);
    }
  }
  public static void main(String[] args) {
    Sharing2 applet = new Sharing2();
    // This isn't an applet, so set the flag and
    // produce the parameter values from args:
    applet.isApplet = false;
    applet.numCounters = 
      (args.length == 0 ? 5 :
        Integer.parseInt(args[0]));
    applet.numObservers =
      (args.length < 2 ? 5 :
        Integer.parseInt(args[1]));
    Frame aFrame = new Frame("Sharing2");
    aFrame.addWindowListener(
      new WindowAdapter() {
        public void windowClosing(WindowEvent e){
          System.exit(0);
        }
      });
    aFrame.add(applet, BorderLayout.CENTER);
    aFrame.setSize(350, applet.numCounters *100);
    applet.init();
    applet.start();
    aFrame.setVisible(true);
  }
} ///:~

我们注意到无论run()还是synchTest()都是“同步的”.假如只同步此中的一个办法,那么另一个便可以安闲轻忽对象的锁定,并可无碍地调用.所以必须记着一个重要的法则:关于拜候某个关键同享资源的全部办法,都必须把它们设为synchronized,不然就不能正常地工作.
目前又碰到了一个新问题.Watcher2永久都不能看到正在举行的事情,因为整个run()办法已设为“同步”.并且由于必定要为每个对象运行run(),所以锁永久不能翻开,而synchTest()永久不会得到调用.之所以能看到这一后果,是因为accessCount根本没有改变.
为办理这个问题,我们能采纳的一个办法是只将run()中的一部份代码断绝出来.想用这个办法断绝出来的那部份代码叫作“关键区域”,并且要用差别的方法来利用synchronized关键字,以设置一个关键区域.Java通过“同步块”供应对关键区域的支持;这一次,我们用synchronized关键字指出对象的锁用于对此中封闭的代码举行同步.以下所示:
synchronized(syncObject) {
  // This code can be accessed by only
  // one thread at a time, assuming all
  // threads respect syncObject's lock
}

在能进入同步块之前,必须在synchObject上获得锁.假如已有其他线程获得了这把锁,块便不能进入,必须等候那把锁被释放.
可从整个run()中删除synchronized关键字,换成用一个同步块包抄两个关键行,从而完成对Sharing2例子的改正.但什么对象应作为锁来利用呢?那个对象已由synchTest()标志出来了——也就是当前对象(this)!所以改正过的run()办法象下面这个模样:
  public void run() {
    while (true) {
      synchronized(this) {
        t1.setText(Integer.toString(count1++));
        t2.setText(Integer.toString(count2++));
      }
      try {
        sleep(500);
      } catch (InterruptedException e){}
    }
  }
这是必须对Sharing2.java作出的唯一改正,我们会看到固然两个计数器永久不会脱离同步(取决于答应Watcher什么时刻查抄它们),但在run()履行期间,仍旧向Watcher供应了充足的拜候权限.
当然,全部同步都取决于程序员能否勤奋:要拜候同享资源的每一部份代码都必须封装到一个得当的同步块里.

2. 同步的效率
由于要为一样的数据编写两个办法,所以无论若何都不会给人留下效率很高的印象.看来仿佛更好的一种做法是将全部办法都设为自动同步,并完好消除synchronized关键字(当然,含有synchronized run()的例子显示出这样做是很不通的).但它也揭暴露获得一把锁并非一种“便宜”筹划——为一次办法调用付出的代价(进入和退出办法,不履行办法主体)至少要累加到四倍,并且按照我们的具体现筹划,这一代价还有大概变得更高.所以假定已知一个办法不会造成冲突,最明智的做法就是撤消此中的synchronized关键字.
  以上是“<b>Java若何同享资源</b>[Java编程]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
  • <b>hosts是什么 hosts文件在什么位置 若何改正hosts</b>
  • <b>在 Windows 8 中手动安装语言包</b>
  • <b>五个常见 PHP数据库问题</b>
  • Windows中Alt键的12个高效快速的利用本领介绍
  • <b>MySQL ORDER BY 的实现解析</b>
  • <b>详解MySQL存储历程参数有三种范例(in、out、inout)</b>
  • <b>Win8系统恢复出来经典的开始菜单的办法</b>
  • <b>Win8系统花屏怎么办 Win8系统花屏的办理办法</b>
  • <b>Windows 7系统下无线网卡安装</b>
  • <b>为什么 Linux不需求碎片整理</b>
  • <b>Windows 8中删除账户的几种办法(图)</b>
  • <b>教你如安在win7下配置路由器</b>
  • 本文地址: 与您的QQ/BBS好友分享!
    • 好的评价 如果您觉得此文章好,就请您
        0%(0)
    • 差的评价 如果您觉得此文章差,就请您
        0%(0)

    文章评论评论内容只代表网友观点,与本站立场无关!

       评论摘要(共 0 条,得分 0 分,平均 0 分) 查看完整评论
    Copyright © 2020-2022 www.xiamiku.com. All Rights Reserved .