java中稍微有些陌生的关键字
1、 instance of
java中,instance of 用来指出某个对象是否为某个特定类的实例,如果是返回一个bool类型,来指出该对象是否为某个特定类或其子类的一个实例
resutl = object instance of class
interface A{} class B implements A { } class C extends B { } public class InstanceOfTest { public static void main(String[] args) { // TODO Auto-generated method stub A a = null; B b = null; boolean result; System.out.println("instanceoftest test case 1: ------------------"); result = a instanceof A; System.out.println("a instanceof A :"+result); result = b instanceof B; System.out.println("b instanceof B :"+result); System.out.println("/ninstanceoftest test case 2: ------------------"); a = new B(); b = new B(); result = a instanceof A; System.out.println("a instanceof A :"+result); result = a instanceof B; System.out.println("a instanceof B :"+result); result = b instanceof A; System.out.println("b instanceof A :"+result); result = b instanceof B; System.out.println("b instanceof B :"+result); System.out.println("/ninstanceoftest test case 3: ------------------"); A b2 = new C(); result = b2 instanceof A; System.out.println("b2 instanceof A :"+result); result = b2 instanceof B; System.out.println("b2 instanceof B :"+result); result = b2 instanceof C; System.out.println("b2 instanceof C :"+result); } }
2、transient
Q:transient关键字能实现什么?
A:当对象被序列化时(写入字节序列到目标文件)时,transient阻止实例中那些用此关键字声明的变量持久化;
当对象被反序列化时(从源文件读取字节序列进行重构),这样的实例变量不会被持久化和回复。例如,当反
序列化对象----数据流(例如,文件)可能不存在是,原因是你的对象中存在类型为java.io.InputStream的变量
,序列化时这些变量引用的输入流无法被打开。
总之当你不需要某个变量被序列化时,则将该变量设置为 transient变量
3、native
java native 方法是指本地方法,当在方法中调用一些不是由java语言写的代码或者在方法中调用java语言直接操纵计算机硬件时声明为native方法。
java中,通过JNI(java native interface ,java本地接口)来实现本地化
native方法一般用于两种情况:
1) 在方法中调用一些不是由java语言写的代码
2) 在方法中用java语言直接操纵计算机硬件
JNI的书写步骤:
a、编写带有native声明的方法的java类
b、使用javac命令编译编写的java类
c、使用java -jni ***来生成后缀名为.h的头文件
d、使用其他语言(C、c++)实现本地方法
e、将本地方法编写的文件生成动态链接库
4、synchronized
Q:为什么要用synchronized这个关键字
A:先看个实例
package com.lost.syn; import java.awt.geom.FlatteningPathIterator; class Account{ String name; float amount; public Account(String name, float amount) { this.name = name; this.amount = amount; } public void deposit(float amt) { float tmp = amount; tmp += amt; try { System.out.println("存入100"); Thread.sleep(100); } catch (Exception e) { // TODO: handle exception } this.amount = tmp; } public void withdraw(float amt) { float tmp = this.amount; tmp -= amt; try { System.out.println("取出100"); Thread.sleep(100); } catch (Exception e) { // TODO: handle exception } this.amount = tmp; } public float getBalance() { return this.amount; } } public class SynDemo { public static int NUM_OF_THREAD = 5000; static Thread[] threads = new Thread[NUM_OF_THREAD]; public static void main(String args[]) { final Account cc =new Account("john",1000.0f); for(int i=0;i<NUM_OF_THREAD; i++) { threads[i] = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub cc.deposit(100.0f); cc.withdraw(100.0f); } }); threads[i].start(); } for(int i=0; i<NUM_OF_THREAD; i++) { try { threads[i].join(); } catch (Exception e) { // TODO: handle exception } } System.out.println("Finally John's Balance is "+cc.getBalance()); } }
Finally John's Balance is 1200.0
Finally John's Balance is 1400.0
线程一 和线程二同时进行 初始balance为1000
线程一存钱 线程二也存钱 同时进行 基数都是1000 存完后 基数编程了1100 而不是1200 此时如果再同时取钱的话 又变成了1000 如果不同时取得话 就变成了900
每次的结果都不一定相同,因为是有很多线程同时在存取。如果你每次运行得到的都是1000,恭喜你,你的电脑配置比较高,所以你可以把线程的数量开的稍微大一些。
这就是多线程中同步的问题,在我们的程序中,Account会同时被多个线程访问,这就是一个竞争资源,通常称作竞态条件。对于这样的多个线程共享的资源我们必须进行同步,以避免一个线程的改动被另一个线程所覆盖。在我们这个程序中,Account中的amount是一个竞态条件,所以所有对amount的修改访问都要进行同步,我们将deposit和withdraw方法进行同步
public synchronized void deposit(float amt) { float tmp = amount; tmp += amt; try { System.out.println("存入100"); Thread.sleep(100); } catch (Exception e) { // TODO: handle exception } this.amount = tmp; } public synchronized void withdraw(float amt) { float tmp = this.amount; tmp -= amt; try { System.out.println("取出100"); Thread.sleep(100); } catch (Exception e) { // TODO: handle exception } this.amount = tmp; }
同步加锁的是对象而不是代码段
如果你的类中有一个同步方法,这个方法可以被两个不同的线程同时执行,只要每一个线程自己创建一个的该类的实例即可。
class Foo extends Thread { private int val; public Foo(int v) { val = v; } public synchronized void printVal(int v) { while(true) { System.out.println(v); } } public void run() { printVal(val); } }
类的同步
要实现真正的断面,你必须同步一个全局对象或者对类进行同步。
class Foo extends Thread { private String name; private String val; // private static Object lock = new Object(); public Foo(String name, String v) { this.name = name; this.val = v; } public void printVal() { synchronized(Foo.class){ while(true) { System.out.println(name+val); } } } public void run() { printVal(); } }
对于String类型 如下例 有jVM的优化机制 “”在内存中只保存一份,除非用new String 重新创建对象
class Foo extends Thread { private String name; private String val; // private static Object lock = new Object(); public Foo(String name, String v) { this.name = name; this.val = v; } public void printVal() { synchronized(val){ while(true) { System.out.println(name+val); } } } public void run() { printVal(); } }
//main 方法中 String value = "printVal"; Foo f1 = new Foo("foo 1:",new String("foo 1")); f1.start(); Foo f2 = new Foo("foo 2:",new String("foo 2")); f2.start(); Foo f1 = new Foo("foo 1:",value ); f1.start(); Foo f2 = new Foo("foo 2:",value ); f2.start();
上面两种关于main中的使用是不一样的
小结:
synchronized关键字的作用域有两种:
1、是某个对象实例内, synchronized aMethod(){} 可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其他线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的丢向实例的synchronized方法是不相干扰的。也就是说,其他线程照样可以同时访问相同类的另一个对象实例中synchronized方法。
2、除了方法前使用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。用法是: synchronized(this){/*区块*/},它的作用域是当前对象;
3、synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){} ,而是变成了f(){}.继承类需要你显示的指定它的某个方法为synchronized方法。
java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)代码块。
三、尤其关键的是,当一个线程访问object的一个synchronized(this) 同步代码块时,其他线程对object中的多有其他synchronized同步代码块的访问将被阻塞。
四、第三个例子同样适用其他同步代码块。也就是说,当一个线程访问object的一个synchronized同步代码块时,它就获得了这个object的对象锁。结果,其他线程对该object对象所有同步代码部分的访问都被暂时组设
五、以上规则对其他对象锁同样适用。
(java中不能在类外定义全局变量,只能通过一个类中定义公用,静态的变量来实现一个全局变量)
synchronized方法控制对类成员变量的访问:每个类实例对应一把锁,每个synchronized方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,伺候被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为synchronized)。(第一次加synchronized的时候)
在java中,不光是类实例,每一个类也对应一把锁,这样我们有可将类的成员函数声明为synchronized,以控制其对类的静态成员变量的访问。
synchronized方法的缺陷:若将一个大的方法声明为synchronized将会大大影响效率,典型地,若将线程类的方法run声明为synchronized,由于在线程的整个声明周期内他一直在运行,因此导致它对本类任何synchronized 方法的调用都永远不会成功。当我们可以通过将访问类成员变量的代码放到专门的方法中,将其声明为synchronized,并在主方法中调用来解决这一问题,但是java为我们提供了更好的解决办法,那就是synchronized块。
2、synchronized 块: 通过synchronized关键字声明synchronized块。
可以针对任意代码块,且可以任意指定上锁的对象,故灵活性较高。
一、当两个并发线程访问同一个对象object 中的这个synchronized同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized同步代码块时,另一个线程仍然可以范文该object中的非synchronized同步代码块。
三、当一个线程访问object的一个synchronized同步代码块时,其他线程仍然可以访问该object 中所有其他synchronized(this)同步代码块的访问将被阻塞。
5、strictfp(strict float point)精确浮点
如果你想让你的浮点运算更加精确,而且不会因为不同的硬件平台执行的结果不一致的话,可以使用关键字 strictfp