Java线程同步方法

CountDownLatch

CountDownLatch主要用来等待一系列线程都完成后,再继续下一步的执行,类似于C++中的join。

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CountDownLatchExample {

	public static void main(String[] args) {
		ExecutorService pool = Executors.newCachedThreadPool();
		final CountDownLatch doneLatch = new CountDownLatch(10);

		for(int i = 0; i < 10; i++) {
			Runnable runnable = new Runnable() {

				@Override
				public void run() {
					try {
						Thread.sleep((long)(Math.random() * 1000));
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println("Thread: " + Thread.currentThread().toString() + " done");
					doneLatch.countDown();
				}
			};
			pool.execute(runnable);
		}
		try {
			doneLatch.await();
			System.out.println("All Thread Done!");
		} catch(InterruptedException e) {
			e.printStackTrace();
		}
		pool.shutdown();
	}
}

CyclicBarrier

CyclicBarrier跟CountDownLatch很相似,它主要用来等待一系列线程都运行到某一步后,再同时继续往下运行。相当于是一个栅栏,只有当所有的线程都到达这个栅栏的时候,栅栏才会打开,各个线程继续往下执行,所以CyclicBarrier有栅栏函数的作用。 CyclicBarrier的构造函数除了指定需要等待的线程数目外,还可以指定一个Runnable对象,由最后一个到达的线程调用。

public CyclicBarrier(int parties, Runnable barrierAction)
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CyclicBarrierExample {
	
	public static void main(String[] args) {
		ExecutorService pool = Executors.newCachedThreadPool();
		final CyclicBarrier barrier = new CyclicBarrier(5);
		
		for(int i = 0; i < 5; i++) {
			Runnable runnable = new Runnable() {
				
				@Override
				public void run() {
					try {
						Thread.sleep((long)(Math.random() * 1000));
						System.out.println("Thread: " + Thread.currentThread().toString() + "step 1 done. "
								+ (barrier.getNumberWaiting() +1) + " thread finished!");
						
						barrier.await();
						System.out.println("Thread: " + Thread.currentThread().toString() + "start step 2 ...");
						
					} catch(InterruptedException e) {
						e.printStackTrace();
					} catch(BrokenBarrierException e) {
						e.printStackTrace();
					}
				}
			};
			pool.execute(runnable);
		}
		pool.shutdown();
	}
}

Semaphore

信号量,这个跟C++中的semaphore用法是一致的,在构造函数中指定资源数目,每个线程在访问临界区的时候都需要首先使用acquire()获得一个资源,完成后使用release()释放资源。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class SemaphoreExample {
	
	public static void main(String[] args) {
		ExecutorService pool = Executors.newCachedThreadPool();
		final Semaphore sem = new Semaphore(3);
		
		for(int i = 0; i < 10; i++) {
			Runnable runnable = new Runnable() {
				
				@Override
				public void run() {
					try {
						sem.acquire();
						System.out.println("Thread: " + Thread.currentThread().toString() + "running ...");
						Thread.sleep((long)(Math.random() * 1000));
						System.out.println("Thread: " + Thread.currentThread().toString() + "done");
						sem.release();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
			pool.execute(runnable);
		}
		pool.shutdown();
	}
}

Android Activity生命周期

Activity生命周期转换图

alt none

  • onCreate(Bundle): Activity生成时调用。如果存在使用OnSaveInstanceState方法保存的信息,将把保存的信息传递给OnCreate的Bundle参数。
  • onStart(): 在Activity即将显示的时候调用。
  • onResume(): 当Activity可以接受用户输入的时候调用。它是开始播放媒体文件的一个很好的时间点。
  • onPause(): Activity转入后台时调用。如果在调用这个方法之后,系统内存不足,这个Activity进程可能被终止掉。
  • onStop(): 暂时不使用Activity时调用这个方法(可能时因为其他Activity启动或者程序即将结束时)。如同onPause()一样:当内存不足时,系统可能会直接终止进出,而不调用这个方法。
  • onRestart(): 调用onStop后,再次显示这个Activity时调用。
  • onDestroy(): Activity即将终止时调用。如同onPause()一样:当内存不足时,系统可能会直接终止进出,而不调用这个方法。
  • onSaveInstanceState(Bundle): 保存实例的状态时调用。这里使用Bundle参数来保存值。当因为内存不足等原因而造成程序终止时,这个函数所保存的值能继续作为参数传递给onCreate()和onRestoreInstanceState(),因此,再次启动程序时就能利用这个传递给Bundle的值恢复之前的状态。
  • onRestoreInstanceState(Bundle): 在恢复实例的状态时调用。通过参数Bundle,可以获取通过onSaveInstanceState()保存的值,这个值与传递给onCreate()的内容相同。虽然采取任何一种方法进行恢复处理都没有问题,但是onRestoreInstanceState的处理方式跟自然。

Activity方法调用时序

alt none alt none

alt none alt none

alt none alt none

alt none

ref: http://developer.android.com/guide/components/activities.html ref:《Android开发秘籍》 顺便推荐一款好用的在线UML工具: http://www.websequencediagrams.com/

Java语言中的静态类

在写Android程序的时候,系统会自动生成一个R.java,这个类中使用了大量的静态类,对一个C++程序员来说,这是个新鲜事物,下面来看看这个神奇的玩意。

静态内部类的语法

public class ExternalClass {
    public static final class InnerClass {
        //...
    }
} 

静态内部类的作用

一般情况很少会用到静态类,但它也并不是一无是处,不然Java也就不会引入这个语法了。静态内部类的一个最大的用处出现在对Java类的测试中,例如:

public class Test {	
	public static void main(String[] args) {
		Other.Test.printx();
	}
}

class Other{
        static class Test {
              Other o = new Other();
              o.printx();       
        }	
	
	public void printx() {
		System.out.println("Other class");
	}
}

静态内部类与非静态内部类

  非静态内部类 静态内部类
修饰符   static
声明静态成员 不能
访问外部类成员 能访问外部类的所有成员 只能访问外部类的静态成员
跟外部类实例的关系 绑定外部类 不需要绑定外部类

Android的R类正是使用了“静态内部类不需要绑定到外部类”这条属性,使得我们可以方便的直接引用R类中常量。

Java语言中的异常处理

java异常分类

异常类层次

alt none

Throwable

Java中所以的异常都是有Throwable继承而来。

Error

Error类层次结构描述了JAVA运行时系统的内部错误和资源耗尽错误。应用程序不应该抛出这种类型的错误对象。如果程序出现了这样的内部错误,除了通告给用户,并尽力使程序安全终止之外,再无能为力。这种情况很少出现。

Exception

在设计JAVA程序时,需要关注Exception层次结构。这个层次结构又分为两个分支:

Runtime Exception

由程序错误导致的异常属于Runtime Exception,相当于C++中的logic_error类。如果出现“Runtime Exception”异常,那么就一定是你的问题。应该通过检测数组下表是否越界来避免ArrayIndexOutOfBoundsException异常;应该通过在使用变量之前检测是否为空来杜绝NullPointerException异常的发生。派生于Runtime Exception的异常包含下面几种情况:

  • 错误的类型转换
  • 数组访问越界
  • 访问空指针

IOException

派生于IOException的异常包含下面几种情况:

  • 试图在文件尾部后面读取数据
  • 试图打开一个错误格式的URL
  • 试图根据给定的字符串查找Class对象,而这个字符串表示的类并不存在

未检查异常和已检查异常

未检查异常

Java语言规范将派生于Error类或RuntimeException类的所以异常称为“未检查异常(unchecked exception)”。

已检查异常

除上面所述的未检查异常外的所以异常都称为“已检查异常(checked exception)”。编译器将核查是否为所有的已检查异常提供了异常处理器。

声明异常

方法应该在其首部使用throws关键字声明所有可能抛出的异常。例如:

public FileInputStream(String name) throws FileNotFoundException

当一个方法有可能抛出多个已检查异常时,那么必须在方法的首部列出所有的异常类。例如:

class MyClass {
    public void MyMethod(String s) throws EOFException, IOException {
        //... ...
    }
}

在自己编写的方法时,不必将所有可能抛出的异常都进行声明。至于什么时候需要在方法中用throws字句声明异常,什么异常必须使用throws字句声明,需要记住在遇到下面4种情况时应该抛出异常:

  • 调用一个抛出已检查异常的方法时,例如,FileInputStream
  • 程序运行过程中发现错误,并且利用throws语句抛出一个已检查异常
  • 程序出现错误,例如,a[-1] = 0会抛出一个ArrayIndexOutOfBoundsException这样的未检查异常
  • Java虚拟机和运行库出现内部异常

如果出现前两种情况之一,则必须告诉调用这个方法的程序员有可能抛出异常。但是,并不需要声明Java的内部错误,即那些从Error继承而来的错误。任何程序代码都具有抛出那些异常的潜能,而我们对其没有任何的控制能力。同样的,也不应该声明从RuntimeException继承的那些未检查异常。例如:

    class MyClass {
       public  void MyMethod(String s) throws ArrayIndexOutOfBoundsException //这里不必要做声明未检查异常 
    }

总之一个方法必须声明所有可能抛出的已检查异常,而未检查异常要么不可控制(Error),要么就应该避免(RuntingException)。如果方法没有声明所有可能发生的已检查异常,编译器就会给出一个错误信息。

子类中的异常

如果在子类中覆盖了超类的一个方法,子类方法中声明的异检查异常不能超过超类方法中声明的异常范围(也就是说,子类中抛出的异常范围更加小,或者根本不抛出异常)。

抛出异常

抛出一个已经存在的异常类,一般步骤如下:

  • 找到一个合适的异常类
  • 创建这个类的一个对象
  • 将对象抛出

例如:

void  MyMethod(Scanner in) throws EOFException {
    while(...) {
        if(!in.hasNext) {//EOF encountered
            if(n < len) 
                throw new EOFException();
        }
    }
}

创建异常

在程序中,可能会遇到任何标准异常类都没有能够充分描述清楚的问题。在这种情况下,我们可以定义一个派生于Exception或其子类的类,例如:

class FileFormatException extends IOException {
    public MyException() {}
    public MyException(String str) {
        super(str);
    }
}

使用MyException:

string readData(BufferedReader in) throws FileFormatException {
    ...
    while(...) {
        if(ch == -1){ //EOF encourntered
            if(n < len)
                throw new FileFormatException();
        }
    }
    return s;
}

捕获异常

Java中捕获异常的方法跟C++中一样,可以使用try catch字句。

捕获单个异常

public void read(String filename) {
    try{
        InputStream in = new InputStream(filename);
        int b;
        while((b = in.read()) != -1) {
            ...
        }
    } catch(IOException e) {
         e.printStackTrace();
    } finally {
        in.close();
    }
}

捕获多个异常

在一个try语句块中可以捕获多个异常类型,并对不同类型异常做不同的处理,例如:

try {
    //可能抛出异常的代码
} catch(MalformatURLException e1) {
    //处理MalformatURLException
} catch(UnknownHostException e2) {
    //处理UnknowHostException
} catch(IOException e3) {
    //处理IOException
} finally {
   //一些抛出异常后的处理
}

与C++语言的比较

  • C++中的logic_error类相当于Java中的RuntimeException
  • C++中的runtime_error类相当于Java中非RuntimeExcepton
  • C++ 中的throw与Java中的throws基本相同,但有一点重要的区别。在C++中,throw说明符是在运行时执行,而不是在编译时执行,也就是说,C++编译器将不处理任何异常说明符
  • C++中如果不给出throw声明,函数可能抛出任何异常。Java中如果没有throws说明符,函数将不能抛出任何异常检查
  • C++中可以抛出任何类型的值,Java中只能抛出Throwable子类的对象

ref:《Java 核心技术》

Nvidia显卡的xorg配置

生成xorg配置

如果发现系统/etc/X11/xorg.conf文件丢失,你可以使用下面的命令生成一个新的xorg.conf文件

$ X --configure

新生成的xorg.conf.new一般在用户目录下,具体路径请查看输出结果,得到xorg.conf.new文件后需要把它拷贝到/etc/X11/下,并且更改文件名为xorg.conf。如果这个自动生成的文件不符合需求就需要根据具体情况做相应的修改。当然,更方便的方法就使从别的机器上拷贝/etc/X11/xorg.conf到你的系统中,针对Nvidia显卡的xorg配置都使通用的,然后再做相应的修改。

单屏xorg的配置

xorg.conf内容

# nvidia-xconfig: X configuration file generated by nvidia-xconfig
# nvidia-xconfig:  version 260.19.44  ([email protected])  Sun Feb 27 21:50:39 PST 2011

Section "ServerLayout"
	InputDevice    "irtouch" "SendCoreEvents"
	Identifier     "Layout0"
	Screen      0  "Screen0"
	InputDevice    "Keyboard0" "CoreKeyboard"
	InputDevice    "Mouse0" "CorePointer"
	Option         "Xinerama" "0"
EndSection

Section "Files"
EndSection

Section "InputDevice"
	# generated from default
	Identifier     "Mouse0"
	Driver         "mouse"
	Option         "Protocol" "auto"
	Option         "Device" "/dev/psaux"
	Option         "Emulate3Buttons" "no"
	Option         "ZAxisMapping" "4 5"
EndSection

Section "InputDevice"
	# generated from default
	Identifier     "Keyboard0"
	Driver         "kbd"
EndSection

Section "Monitor"
	Identifier     "Monitor0"
	VendorName     "Unknown"
	ModelName      "Unknown"
	HorizSync       28.0 - 33.0
	VertRefresh     43.0 - 72.0
	Option         "DPMS"
EndSection

Section "Device"
	#Option        "Rotate" "CW"
	Identifier     "Device0"
	Driver         "nvidia"
	VendorName     "NVIDIA Corporation"
	BusID          "PCI:1:0:0"
EndSection

Section "Screen"
	Identifier     "Screen0"
	Device         "Device0"
	Monitor		   "Monitor0"
	Option         "TwinView" "0"
	Option         "ConnectedMonitor" "DFP-1"
	Option         "metamodes" "DFP-1: 1920x1080 +0+0"
	Option         "CustomEDID" "DFP-1:/etc/X11/edid.bin"
	SubSection     "Display"
		Depth      24
	EndSubSection
EndSection

### Touch Configuration Beginning ###
section "InputDevice"
	Identifier "irtouch"
	Driver "irtouch"
	Option "ScrenNumber" "0"
	Option "SendCoreEvents"
	Option "MinX" "0"
	Option "MinY" "0"
	Option "MaxX" "4095"
	Option "MaxY" "4095"
	Option "SwapXY" "0"
EndSection
### Touch Configuration End ###

xorg.conf解析

  • xorg.conf中的注释语句以’#’开头,遵守标准的shell注释。
  • xorg.conf配置以section为单位,每一个section都是以”<section>”开始,以””为结尾。
  • xorg.conf中”ServerLayout”,”Monitor”,”Device”,”Screen” section都有一个“Identifier”字段,这个字段可以用来把这4个section联系起来。

ServerLayout

用来配置Xserver的一些属性,比如Screen的摆放、输入输出设备等。

  • Screen 0 “Screen0”: 当前系统中使用了一个Screen,表识为0, 它对应到下面”Screen” section中表识为”Screen0″的Screen配置。当有多个Screen的时候可以使用这个字段来控制Screen的显示位置,在这个单屏系统中没有使用到这些特性。

Monitor

这个section用来配置显示器的一些信息,比如显示器的刷新率、分辨率等等。如果系统使用了EDID,就不需要更改这个section。只有当需要输出一个显示器不支持的分辨率并且不使用CustomEDID的时候才需要在这里指定刷新率、分辨率等内容。

Device

提供显卡硬件的信息。

  • BusID “PCI:1:0:0”: 系统显卡的PCI号。当有多个显卡的时候,就需要指定本Device对应哪一块显卡,PCI号可以

用下面的命令获得:

$ lspci | grep vga -i

可能的输出为:

01:00.0 VGA compatible controller: NVIDIA Corporation GT216 [GeForce GT 220] (rev a2)

把01:00.0转换成PCI:1:0:0 即是这块显卡在系统中的PCI号。

  • Option “Rotate” “CW”: 用来控制Xserver的旋转状态,可能的值有”CW”, “CCW”,分别表示顺时针和逆时针旋转90度。需要注意的是这里的旋转和X上层应用软件的旋转不是一回事。

Screen

这个section具体配置当前X的输出属性,包括输出分辨率,输出位置等。

  • Identifier “Screen0”: 本Screen的表识,被”ServerLayout”使用
  • Device “Device0”: 本Screen对应的硬件设备
  • Monitor “Monitor0”: 本Screen对应的显示器
  • Option “TwinView” “0”: 是否使用TwinView输出,TwinView可以简单理解成一块设备是否用做双屏显示,具体含义请查看“名词解释”,或者google之。
  • Option “ConnectedMonitor” “DFP-1”: 标志本Screen所使用的输出接口。可能的值有:
CRT-0: 一般是显卡的CRT输出口
DFP-1: 一般是显卡的DVI输出口
DFP-2: 一般是显卡的HDMI输出口

注:以上值可能会由于主板的不同出现不同的对应关系。

  • Option “metamodes” “DFP-1: 1920x1080_60 +0+0”: 这里给DFP-1(一般是DVI输出)指定一个分辨率(1920×1080)和偏移位置(+0+0)。显示器的左上角坐标为(0, 0),往右为X正轴,往下为Y正轴。Option “CustomEDID” “DFP-1:/etc/X11/edid.bin”: 告知Xserver不要读取显示器本身的EDID,使用这个指定的EDID,通常不推荐使用这个方式,但是当我们需要输出一个显示器不支持的分辨率时就需要用到这个属性。需要注意的是这里指定的EDID需要和显示器兼容,否则将输出黑屏,不兼容的情况包括EDID大小不一致,是否带声音等。

  • SubSection “Display”: xorg.conf支持子section,子section以”SubSection”开始,以”EndSubSection”结束。Depth 24: 指定本Screen的输出色深。可能的值有8, 16, 24, 32 。

InputDevice

配置xserver需要响应的输入设备属性,上面的例子展示的是”irtouch”公司的触摸屏配置。一般这个section由系统自动检测生成或者在安装输入设备驱动的时候自动添加。

双屏xorg的配置

xorg.conf内容

# nvidia-xconfig: X configuration file generated by nvidia-xconfig
# nvidia-xconfig:  version 260.19.44  ([email protected])  Sun Feb 27 21:50:39 PST 2011

Section "ServerLayout"
	InputDevice    "irtouch" "SendCoreEvents"
	Identifier     "Layout0"
	Screen      0  "Screen0"
	InputDevice    "Keyboard0" "CoreKeyboard"
	InputDevice    "Mouse0" "CorePointer"
	Option         "Xinerama" "0"
EndSection

Section "Files"
EndSection

Section "InputDevice"
	# generated from default
	Identifier     "Mouse0"
	Driver         "mouse"
	Option         "Protocol" "auto"
	Option         "Device" "/dev/psaux"
	Option         "Emulate3Buttons" "no"
	Option         "ZAxisMapping" "4 5"
EndSection

Section "InputDevice"
	# generated from default
	Identifier     "Keyboard0"
	Driver         "kbd"
EndSection

Section "Monitor"
	Identifier     "Monitor0"
	VendorName     "Unknown"
	ModelName      "Unknown"
	HorizSync       28.0 - 33.0
	VertRefresh     43.0 - 72.0
	Option         "DPMS"
EndSection

Section "Device"
	#Option        "Rotate" "CW"
	Identifier     "Device0"
	Driver         "nvidia"
	VendorName     "NVIDIA Corporation"
	BusID          "PCI:1:0:0"
EndSection

Section "Screen"
	Identifier     "Screen0"
	Device         "Device0"
	Monitor		   "Monitor0"
	Option         "TwinView" "1"
	Option         "ConnectedMonitor" "DFP-1, DFP-2"
	Option         "metamodes" "DFP-1: 1920x1080 +0+0, DFP-2: 1920x1080 +0+1080"
	Option         "CustomEDID" "DFP-1:/etc/X11/edid.bin; DFP-2: /etc/X11/edid.bin"
	SubSection     "Display"
		Depth      24
	EndSubSection
EndSection

### Touch Configuration Beginning ###
section "InputDevice"
	Identifier "irtouch"
	Driver "irtouch"
	Option "ScrenNumber" "0"
	Option "SendCoreEvents"
	Option "MinX" "0"
	Option "MinY" "0"
	Option "MaxX" "4095"
	Option "MaxY" "4095"
	Option "SwapXY" "0"
EndSection
### Touch Configuration End ###

xorg.conf解析

这里所谓的双屏是指由一块显卡进行两路输出(这里假设使用了DVI和HDMI输出,DVI对应到DFP-1,HDMI对应到DFP-2)。 跟单屏的配置比较会发现,大部分内容相同,主要区别出现在”Screen” section中:

  • Option “TwinView” “1”: 打开Xserver的双屏配置。
  • Option “ConnectedMonitor” “DFP-1, DFP-2”: 设置输出接口
  • Option “metamodes” “DFP-1: 1920×1080 +0+0, DFP-2: 1920×1080 +0+1080″: 这里需要为每一个输出接口设置相应的分辨率和偏移量。”+0+1080″把HDMI(DFP-2)输出到(0,1080)处,上面的实际上配置了这两个屏按垂直摆放。同理,水平摆放的配置为”+1920+0” 。
  • Option “CustomEDID” “DFP-1:/etc/X11/edid.bin; DFP-2: /etc/X11/edid.bin”: 同时为DFP-1,DFP-2指定了EDID。按需配置,可以只设置一个接口或者两个接口使用不一样的edid.bin文件。
  • 一个细节问题: “metamodes”属性中使用 逗号 作为分割符,而在”CustomEDID”属性中使用 分号 作为分割符。

输出非正常分辨率

这里所谓的非正常分辨率仅仅是指显示器不支持的分辨率,比如要在一台不支持1440×900的显示器上使用1440×900。有如下两种方法:

指定EDID法

  • 提供CustomEDID: 当xorg.conf中的Screen section被指定了CustomEDID属性,那么Xserver将不会读取物理显示器中的EDID,而是尝试加载你所指定的edid文件,比如”DFP-1:/etc/X11/edid.bin”,Xserver将读取/etc/X11/edid.bin中的配置,当然前提是确保你指定的EDID中有你需要的分辨率(这里是1440×900)。

指定”Screen”的输出分辨率:

Option         "metamodes" "DFP-1: 1440x900_60 +0+0"
  • 重启X

指定Modeline法

  • 生成Modeline: 生成Modeline的命令有:cvt, gtf, xvidtune。这里使用一般linux发行版自带的cvt: cvt命令的格式为:cvt 横向分辨率,纵向分辨率 刷新率 所以生成1440×900 60HZ分辨率的命令如下:
$ cvt 1440 900 60

输出:

Modeline "1440x900_60.00"  106.50  1440 1528 1672 1904  900 903 909 934 -hsync +vsync
提供Modeline行: 在对应的”Monitor” section中写入下面这行:
Modeline "1440x900_60.00"  106.50  1440 1528 1672 1904  900 903 909 934 -hsync +vsync
添加完 Modeline后就可以设置”Screen”的输出分辨率:
Option         "metamodes" "DFP-1: 1440x900_60 +0+0"
这里1440x900_60必须跟Modeline中的名字相同,否则xserver将找不到这个分辨率。

最后需要设置”Device”的如下属性:

Option         "ExactModeTimingsDVI" "True"
Option         "ModeValidation" "NoDFPNativeResolutionCheck"
Option         "FlatPanelProperties" "Scaling=Native"
  • 重启X,检查输出分辨率或者使用xrandr命令检查当前分辨率

可能出现的问题: 刷新频率是一个需要做微调的选项。受限以物理显示器的带宽,如果显示器使用60HZ生成的Modeline无法显示,那么需要适当的降低这个数,比如50HZ。

名词解释

TwinView

双显示器架构。在配备 NVIDIA TwinView™ 架构的情况下,单个 GPU 最终支持多显示屏幕技术。如果不是在单个显示屏的有限范围内出现堆叠的窗口,而是将不同的工作分别显示在多个显示屏幕上,效果会怎样?金融分析员可以利用一台显示器跟踪每一个数据流。图形艺术家可以将一个完整的显示屏幕用来显示调色板,而将另一个显示屏幕用来进行编辑。想象一下一边观看晚间新闻一边查收电子邮件会有怎样的感觉。支持多种显示选件(例如数字平面屏幕、RGB 显示器、电视机和模拟平面屏幕)可提供量身定做的视觉解决方案,从而满足个人需求并提高生产力。

Xinerama

Xinerama是X窗口系统的一个扩展,它使得基于X的应用程序可以把一个或多个物理显示器作为一个虚拟显示器来使用。

EDID

EDID(Extended Display Identification Data)是一种 VESA 标准数据格式,其中包含有关监视器及其性能的参数,包括供应商信息、最大图像大小、颜色设置、厂商预设置、频率范围的限制以及显示器名和序列号的字符串。这些信息保存在 display 节中,用来通过一个 DDC(Display Data Channel)与系统进行通信,这是在显示器和 PC 图形适配器之间进行的。最新版本的 EDID 可以在 CRT、LCD 以及将来的显示器类型中使用,这是因为 EDID 提供了几乎所有显示参数的通用描述。

Modeline

它可以为服务器提供有关所连接的计算机显示器的信息,以及如何在指定的显示分辨率下对其进行驱动的信息。(最初在 XFree86 上是在 XF86Config 中。)现在,在很多 Linux/UNIX 版本中,modeline 都不再需要了,因为服务器会在启动时根据各种参数来计算配置。但是当我们需要输出一个物理显示器不支持的分辨率的时候就需要为xserver写入Modeline。 一个modeline有10个参数,首先是一个指定分辨率的标签。第 2 个参数指定的是像素时钟频率(单位为 MHz)。下面是两组 4 个数字。第 1 组指定了 x 分辨率(宽度)以及相关参数;第 2 组指定的是 y 分辨率(高度)。另外,还可以添加其他参数作为选项来控制水平和垂直的同步值,还有一些选项可以控制隔行模式和双屏模式。