mount是linux很常用的命令,用于挂载各种设备(包括本地block设备,NFS,虚拟设备等),umount用于卸载设备。如果挂载一个设备到一个目录中,则通过该目录可以访问设备的文件(必须有权限访问),而原来目录的内容会暂时性隐藏(不会覆盖,卸载后恢复可见)。
mount最常用的使用方式为:
mount device dir
比如 mount /dev/sda1 /mnt
这是mount会自动检测设备的文件系统(如果可能的话,比如fstab,mtab中配置有),如果检测失败,需要指定文件系统类型,使用-t选项指定,比如
mount -t btrfs /dev/sda1 /mnt
/etc/fstab是系统默认挂载的配置,在系统启动时会自动挂载该文件下的设备(设置选项noauto除外。
如果你修改了该文件,你也可以使用 mount -a使系统重新读取该文件进行挂载。
在/etc/mtab会记录当前的挂载状况(在/proc/mounts也记录),当使用mount命令不加任何参数时,默认打印该文件的内容。
你也可以使用-l选项打印当前的挂载状况,使用-t选项过滤打印的文件系统类型。
以前一个设备只能挂载在一个地方,从内核2.4以后,支持把一个目录挂载到另一个目录,这时相当于相同文件内容可以同时有多个访问点(这在chroot中很有用,想想我在新的root中怎么访问/proc /dev目录),使用--bind 或者-B选项挂载目录
比如
mount --bind -t tmpfs /dev/ newDev
mount --bind -t proc /proc newProc
注意使用bind选项只能挂载指定目录下的内容,如果该目录下又有子挂载点,不会自动挂载,使用rbind选项,可以递归挂载,甚至可以挂载/ 到另一个目录中。
比如
mount --rbind -t ext4 / newRoot
不过挂载了就不能卸载了,因为该目录正使用(busy),可以使用lsof命令查看(可以使用--move选项,见以下)。
有时我们不想有人bind,可以使用mount --make-unbindable或者--make-runbindable(递归式)选项设置。比如
mount --make-runbindable /
不能再bind根目录了。
--move选项可以把一个挂载点移动到另一个目录,如
mount --move -t ext4 /mnt /media
-r(或者-o ro)选项指定只读挂载,访问挂载点只能读取内容,不能写,-w(或者-o rw)指定挂载为读写方式,这也是默认方式。
-o 指定挂载选项(多个选项使用逗号分隔),以上已经介绍了ro和rw选项,下面简单介绍下挂载选项:
auto ,再/etc/fstab下指定,使用mount -a时或者系统启动时自动挂载,使用noauto相反。
defaults使用默认挂载选项,相当于rw,suid,dev,exec,auto,nouser,async
dev 说明这是字符设备或者块设备,而不是虚拟设备,相反nodev说明可能是虚拟设备
exec,在挂载点可以执行文件,noexec说明在挂载点上不能执行文件,有一次我在家目录下不小心指定了noexec,写了个c程序,运行./a.out出错,后面发现原来是指定了noexec选项
group 一般文件系统挂载只能root身份才有权限,在fstab下指定group,则属于设备组的用户可以挂载。
owner指定设备的所有者可以挂载,比如某设备属于Mary,则root和Mary都有权限挂载。
remount,重新挂载已经挂载的设备,用于覆盖原来的选项,比如原来的文件系统/dev/sda1是只读的,挂载在/mnt下,则可以使用
mount -o remount,rw /dev/sda1 /mnt 重新挂载,并且可读写。
user 用于fstab文件,任何普通用户都可以挂载该设备。
nouser用于fstab,表明只有root可以挂载,这是默认行为。
还有一些选项,专门针对指定的文件系统,比如ext2的errors。
mount还可以用于挂载loop设备,比如iso镜像,img文件等。此时需要指定文件系统类型(-t)和loop选项,比如
mount -t ext4 -o loop ubuntu.iso /mnt
mount -t iso9660 -o loop ubuntu.iso /mnt
卸载loop设备使用命令losetup -d 或者umount -d
试一下
dd if=/dev/zero of=tmp.img bs=500m count=2
mkfs.ext4 tmp.img
mount -t ext4 tmp.img /mnt
使用mount可以挂载iso文件,但磁盘格式为qcow2则不能直接挂载了,可以查看以前的文章挂载http://krystism.is-programmer.com/posts/47074.html。
在java6中有一个新类Console,能够实现无回显输入,用于安全输入!以下是代码样例:
import java.io.*;
import java.util.*;
public class ConsoleDemo {
public static void main(String[] args) {
Console console = System.console();
if (console == null) {
System.err.println("Failed to get console!");
return;
}
String name = console.readLine("Please type your name:");
char[] password1 = null;
char[] password2 = null;
console.printf("Your name is %s\n", name);
password1 = console.readPassword("Please type your password:");
password2 = console.readPassword("Please type your password again:");
if (!Arrays.equals(password1, password2)) {
System.err.println("Password doesn't match the confirmation.");
return;
}
console.printf("Hi, %s, Your password is '%s'\n", name, new String(password1));
Arrays.fill(password1, '\0'); /* 安全清理 */
Arrays.fill(password2, '\0');
}
}
这个问题很简单,就是在一个无序数组中判断某个元素是否存在,当然如果自己定义数据结构,可以使用trie,hash,如果不要求完全准确,允许误判,还能使用布隆!显然不能使用二分搜索,因为数组是无序的!当我们要经常搜索时,排序是必要的,或者使用其他数据结构。
这篇文章讨论了下http://www.programcreek.com/2014/04/check-if-array-contains-a-value-java/#more-12168,于是自己测试了下,下面是我的代码(必须使用java8版本以上):
import java.util.*;
interface StringPolicy {
boolean contains(String[] arr, String value);
}
interface LongPolicy {
boolean contains(long[] arr, long value);
}
class Policies {
public static boolean useList(String[] arr, String value) {
return Arrays.asList(arr).contains(value);
}
public static boolean useList(long[] arr, long value) {
return Arrays.asList(arr).contains(value);
}
public static boolean useSet(String[] arr, String value) {
return new HashSet<>(Arrays.asList(arr)).contains(value);
}
public static boolean useSet(long[] arr, long value) {
return new HashSet<>(Arrays.asList(arr)).contains(value);
}
public static boolean useLoop(String[] arr, String value) {
for (String s : arr) {
if (s.equals(value))
return true;
}
return false;
}
public static boolean useLoop(long[] arr, long value) {
for (long l : arr) {
if (l == value)
return true;
}
return false;
}
public static boolean useStream(String[] arr, String value) {
return Arrays.stream(arr).anyMatch(value::equals);
}
public static boolean useStream(long[] arr, long value) {
return Arrays.stream(arr).anyMatch(l -> l == value);
}
public static boolean useParallelStream(String[] arr, String value) {
return Arrays.stream(arr).parallel().anyMatch(value::equals);
}
public static boolean useParallelStream(long[] arr, long value) {
return Arrays.stream(arr).parallel().anyMatch(l -> l == value);
}
}
public class SearchDemo {
public static void fill(String[] arr) {
for(int i = 0; i < arr.length; ++i) {
arr[i] = String.valueOf(i + 1);
}
}
public static void fill(long[] arr) {
for (int i = 0; i < arr.length; ++i) {
arr[i] = i + 1;
}
}
public static void fill(String[] arr, String value) {
Arrays.fill(arr, value);
}
public static void fill(long[] arr, long value) {
Arrays.fill(arr, value);
}
public static void test(String name, StringPolicy p, String[] arr, String value, int times) {
long start = System.nanoTime();
for (int i = 0; i < times; ++i) {
p.contains(arr, value);
}
long end = System.nanoTime();
long d = (end - start) / 1_000_000;
System.out.printf("%s: %d\n", name, d);
}
public static void test(String name, LongPolicy p, long[] arr, long value, int times) {
long start = System.nanoTime();
for (int i = 0; i < times; ++i) {
p.contains(arr, value);
}
long end = System.nanoTime();
long d = (end - start) / 1_000_000;
System.out.printf("%s: %d\n", name, d);
}
public static void main(String[] args) {
String[] arr1 = new String[10_000];
long[] arr2 = new long[10_000];
fill(arr1);
fill(arr2);
System.out.println("******************* String **************************");
test("useLoop", Policies::useLoop, arr1, "A", 10_000);
test("useList", Policies::useList, arr1, "A", 10_000);
test("useSet", Policies::useSet, arr1, "A", 10_000);
test("useStream", Policies::useStream, arr1, "A", 10_000);
test("useParallelStream", Policies::useParallelStream, arr1, "A", 10_000);
System.out.println("******************* Long **************************");
test("useLoop", Policies::useLoop, arr2, -1, 10_000);
test("useList", Policies::useList, arr2, -1, 10_000);
test("useSet", Policies::useSet, arr2, -1, 10_000);
test("useStream", Policies::useStream, arr2, -1, 10_000);
test("useParallelStream", Policies::useParallelStream, arr2, -1, 10_000);
}
结果输出是:
众所周知,一般使用java实现单例模式有两种方法,分别为急切式(饥饿式)和双重加锁式,急切式就是在声明时即创建,这样在类加载时就已经创建好了,即时我们可能并不不需要它,它的生命周期是永久的,造成内存泄漏的可能!第二种方式是lazy的,只有在使用时创建,实现了延迟加载。代码为
1.急切式
class Singleton {
private final static Singleton instance = new Singleton();
private Singleton(){
}
public static Singleton getInstance() {
return instance;
}
}
2. 双重加锁式
class Singleton {
private volatile static Singleton instance = null;
private Singleton(){
}
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
还有一种方法是使用内部类的方法,这主要为克服方法1中的问题,既能实现延迟加载,又能保证线程安全,而且性能不错。代码为:
class Singleton {
private Singleton() {
}
private static class Holder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
以上方法都是通过使用private构造方法来阻止外部直接创建对象,但如果使用反射机制,则不能保证实例的唯一性了!!!
public class SingletonDemo {
//@SuppressWarnings("unchecked")
//public static <T> T newInstance(Class<?> cl) {
// T t = null;
// try {
// t = (T)cl.newInstance(); /* 只能调用public构造方法 */
// } catch(Exception e) {
// e.printStackTrace();
// }
// return t;
//}
@SuppressWarnings("unchecked")
public static <T> T newInstance(Class<?> cl) {
T t = null;
try {
Constructor<?> constructor = cl.getDeclaredConstructor();
constructor.setAccessible(true);
t = (T)constructor.newInstance();
} catch(Exception e) {
e.printStackTrace();
}
return t;
}
@SuppressWarnings("unchecked")
public static <T> T newInstance(Class<?> cl, Class<?>...args) {
T t = null;
try {
Constructor<?> constructor = cl.getDeclaredConstructor(args);
constructor.setAccessible(true);
t = (T)constructor.newInstance("name", 1);
} catch(Exception e) {
e.printStackTrace();
}
return t;
}
public static void main(String[] args) {
Singleton instance = Single.INSTANCE;
Singleton s1 = newInstance(Singleton.class, String.class, int.class);
Singleton s2 = newInstance(Singleton.class, String.class, int.class);
//Tmp t1 = newInstance(Tmp.class);
//Tmp t2 = newInstance(Tmp.class);
//System.out.println(s1 == s2);
//System.out.println(t1 == t2);
}
}
Joshua Bloch (Effect java 作者)提出一种新的方法实现单例模式,就是使用Enum(其实也是类,一种特殊的类,构造方法必须是private ,final的)!如下:
enum Singleton {
INSTANCE;
public void sayHi() {
System.out.println("Hi");
}
}
这样当试图通过反射机制创建对象时,会抛出异常!
从java7开始在concurrent包中加入了Phaser类,它几乎可以取代CountDownLatch和CyclicBarrier, 其功能更灵活,更强大,支持动态调整需要控制的线程数。下面以一个具体实例说明这个Phaser类的用处,相信理解这个例子后,其功能不言而喻。
例子:有若干考生参加考试,考试科目是统一的,考试顺序为语文、数学、英语共三门,若其中一门挂科,则不能参加后面的考试。现在假设考试时间不受限制,开考时间以最后一名考完上一科时间为准,即先考完的考生并且成绩合格,需要参加下一门考试,则必须等待所有考生考完当科。
import java.util.*;
import java.util.concurrent.*;
class Examinee implements Runnable {
public static Random random = new Random(new Date().getTime());
private String name;
private Phaser phaser;
private int english;
private int chinese;
private int math;
public Examinee(String name, Phaser phaser) {
this.name = name;
this.phaser = phaser;
}
public boolean english() {
int time = random.nextInt(10);
try {
TimeUnit.SECONDS.sleep(time); /* 考试时间是一个随机数 */
} catch (Exception e) {
e.printStackTrace(System.err);
}
english = random.nextInt(101) ; /* 假定考试成绩是随机的 */
if (english < 60) {
System.out.printf("%s Failed to pass English!\n", name);
phaser.arriveAndDeregister(); /* 考试不合格,取消考试资格 */
return false;
} else {
phaser.arriveAndAwaitAdvance(); /* 通过考试,可以进行下一门考试 */
return true;
}
}
public boolean chinese() {
int time = random.nextInt(10);
try {
TimeUnit.SECONDS.sleep(time);
} catch (Exception e) {
e.printStackTrace(System.err);
}
chinese = random.nextInt(101) ;
if (chinese < 60) {
System.out.printf("%s Failed to pass Chinese!\n", name);
phaser.arriveAndDeregister();
return false;
} else {
phaser.arriveAndAwaitAdvance();
return true;
}
}
public boolean math() {
int time = random.nextInt(10);
try {
TimeUnit.SECONDS.sleep(time);
} catch (Exception e) {
e.printStackTrace(System.err);
}
math = random.nextInt(101) ;
if (math < 60) {
System.out.printf("%s Failed to pass Math!\n", name);
phaser.arriveAndDeregister();
return false;
} else {
phaser.arriveAndAwaitAdvance();
return true;
}
}
public void showInfo() {
System.out.printf("%s\tChinese:%d\tEnglish:%d\tMath:%d\n", name, chinese, english, math);
phaser.arriveAndDeregister();
}
@Override
public void run() {
phaser.arriveAndAwaitAdvance(); /* 等待考生做好准备,即在同一个起跑线上 */
System.out.printf("%s is ready!\n", name);
if (!chinese() || !english() || !math())
return;
showInfo(); /* 只显示所有科目均合格的考生分数 */
}
}
public class PhaserDemo2 {
public static void main(String[] args) {
final String[] names = {"Jim", "Hary", "Mary", "Jhon", "Ali", "Lucy", "Wang", "Zhang", "Li", "Uhm", "Hey", "Gu", "Asu", "Who"};
Phaser phaser = new Phaser(names.length);
List<Thread> threads = new ArrayList<>(names.length);
for (String name : names) {
threads.add(new Thread(new Examinee(name, phaser), name)); /* 创建各个考生线程 */
}
for (Thread t : threads) {
t.start(); /* 开始考试 */
}
for (Thread t : threads) {
try {
t.join(); /* 等待考试结束 */
} catch (InterruptedException e) {
e.printStackTrace(System.err);
}
}
System.out.printf("Terminal ? %s\n", phaser.isTerminated());
}
}
由上面的例子,可以看出Phaser的功能。其中arrive方法很像CountDownLatch的countDown方法和CyclicBarrier的await方法,请自行比较之!Phaser类还有很多其他的功能,可以查看其API文档。