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文档。