Java SE series:2. enhance your java basis! [doc chm: jdk6api Chinese reference]
1. javaee(Web) and Android
2. how to use eclipse and break point debuging in eclipse, as to java web, use myeclipse:
shortcut keys: ,do not use Chinese or space in workspace path, configure JRE default, as jdk already has jre, we just configure with jdk path! but if we have a project from others, we better use myeclipse default, coz on different machines, JRE path varies.
3. create a new class, need to specify package name, super class use default, check static void main method stub and inherited abstract method when first entry.
4. right click project and select properties, then configure project properties, check java compiler and compile, so, be aware, your compiler version and your jre version should at least be the same, if we meet with version problems, we should configure project java build path, remove old default libries and add JRE system library into build_path, in this way, our compiler and jre environment can be configured the same. But the higher version will comply with lower.
the same with vs project .net framework target version.
eg: import java.io.file, we can use copy(src,dest), FileNotFoundException,FileInputStream,FileOutputStream,existFile(src), inputstream.read(buffer)>0 and io exceptions, right click project and click debug as java application to debug. F5 to step into the method, F6 to step out like F11, F7 to step out a method like F10 in vs. remember to stop JVM and clear all breakpoints after debugging, we can watch the args while debugging.
F5: step into, F6: step over,F7: step return,drop to frame,resume
5. Ho to configure eclipse shotcut keys: window->preference, select keys under General to configure the shortcut keys and apply. use alt+/ for hints!, repeatly press ctrl+1 to repaidly restore errors. ctrl+shift+o to automatically import package. ctrl+ship+f to auto layout it, ctrl+leftclick to navigate to source, goto java path and import src.zip using file pattern, use alt+left arrow and right arrow to navigate when navigating src,ctrl+shift+/ to comment and ctrl+shift+\ to uncomment,F2 to see method description, window-> reset perspective to reset window layout same with VS.
const value should be upper case, ctrl+shift+x/y to change upper case and lower case. ctrl+alt+ down arrow to copy current line. alt+up/down arrow to toggle current and next line order, watching class hierarchy, press ctrl+t, press ctrl+shift+t to directly see the code source!
ctrl+shift+L to see all shortcut in eclipse.c
6. junit test framework: create a test class for your src code, to use junit, just add @Test as annotation, press ctrl+1 to see hints! right click the method or the whole class, then select run as jUnit Test, see result from jUnit window. use @Before and @After when running test method to add as interceptor,@BeforeClass and @AfterClass as interceptor of the whole class[class interceptor is not so often used]. we can now use Assert. in jUnit now.
7. About java 5 enhancements:
import static: eg: import static java.lang.system.out; import static java.lang.Math.*; same with vs using =, but ctrl+1 is definitely faster.
wrap and unwrap boxing; eg: Integer i=1/(new Integer(1));(jdk 5+); int j=i;
typical usage: new ArrayList().add(1/(old way in jdk 1.4) new Integer(1)), really useful. list.iterator, it.hasNext(); int k=(Integer) it.next();
8. enhanced for loop: eg int arr[] =(1,2,3); for(int num: arr){} Map map=new HashMap(); map.put("1","aaa");Set set=map.keySet(); Iterator it=set.iterator(); while(it.hasNext()){String key=(String)it.next(); String value=(String)map.get(key); } HashMap is not sequencial! remember, when it is stored, the order is different from your storage order! if we want the order, just use LinkedHashMap() when you need order!!! or we can use map.entrySet() to get keyvalue collections, then iterate it to get the entry(Map.Entry as key value pair) then value of the entry. we can use for like (for..in) to iterate set! this for loop only suits reading data. but pay attention to reference type like String. ArrayList.get(0), it defines an argument to iterate. never change set data! if we want to modify data in a list, we should use traditional ways, i.e. using for(int i=0;...)
9. [07]
High Concurrency In Java Solution Candidate
ThreadLocal是什么? 历史 早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。 定义 ThreadLocal很容易让人望文生义,想当然地认为是一个“本地线程”。其实,ThreadLocal并不是一个Thread,而是Thread的局部变量,也许把它命名为ThreadLocalVariable更容易让人理解一些。 我们可以这样理解:把一个线程比喻为一个类,ThreadLocal即是这个类中的成员变量,类中的多个方法可以调用。 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。 这里的副本不是什么引用或者啥的,而是new出来的一个新对象,每个线程只维护自己的对象。 解决了两类问题 线程间通信 线程并发问题 一个线程内部通信 例如:封装Connection ThreadLocal与Synchronized区别 相同 ThreadLocal和线程同步机制相比有什么优势呢?ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。 不同点 在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。 而ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。 ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。 下面例子中我们把Connection对象放入ThreadLocal中,我们的评教系统中也这样进行封装,可以确保一个线程中唯一实例,这样方便了事务调用。 ThreadLocal泛型 由于ThreadLocal中可以持有任何类型的对象,低版本JDK所提供的get()返回的是Object对象,需要强制类型转换。但JDK 5.0通过泛型很好的解决了这个问题,在一定程度地简化ThreadLocal的使用,代码清单 9 2就使用了JDK 5.0新的ThreadLocal<T>版本。 本质区别 概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。 以时间换空间 即枷锁方式,某个区域代码或变量只有一份节省了内存,但是会形成很多线程等待现象,因此浪费了时间而节省了空间。 空间换时间 为每一个线程提供一份变量,多开销一些内存,但是呢线程不用等待,可以一起执行而相互之间没有影响。 这是两种不同的思路,值得借鉴和学习。 实例应用 ThreadLocal封装Connection对象,如下代码 代码 package com.bjpowernode.drp.util; import java.net.ConnectException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import com.sun.org.apache.bcel.internal.generic.NEW; /** * 采用ThreadLocal封装Connection,可以防止线程安全 * @author LLS * */ public class ConnectionManager { private static ThreadLocal<Connection> connectionHolder=new ThreadLocal<Connection>(); /** * 得到Connection * @return */ public static Connection getConnection() { //如果再当前线程中已经绑定相应的Connection则取出来 Connection conn=connectionHolder.get(); //如果没有绑定 if (conn==null) { try{ JdbcConfig jdbcConfig=xmlConfigReader.getInstance().getJdbcConfig(); Class.forName(jdbcConfig.getDriverName()); conn=DriverManager.getConnection(jdbcConfig.getUrlName(), jdbcConfig.getUserName(), jdbcConfig.getPasswordName()); //将Connection设置到变量ThreadLocal中 connectionHolder.set(conn); }catch(ClassNotFoundException e){ e.printStackTrace(); throw new ApplicationException("系统错误,请联系管理员!"); } catch (SQLException e) { e.printStackTrace(); throw new ApplicationException("系统错误,请联系管理员!"); } } return conn; } public static void close(Statement pstmt) { if(pstmt !=null) { try { pstmt.close(); } catch (SQLException e) { e.printStackTrace(); } } } /** * 关闭结果集 * @param rs */ public static void close(ResultSet rs) { if(rs!=null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } } /** * 关闭连接 */ public static void closeConnection() { Connection conn=connectionHolder.get(); if (conn!=null) { try { conn.close(); //从集合ThreadLocal中清除掉 connectionHolder.remove(); } catch (SQLException e) { e.printStackTrace(); } } } /** * 开启事务 * @param conn */ public static void beginTransation(Connection conn) { try { if(conn!=null) { if(conn.getAutoCommit()) { conn.setAutoCommit(false); } } } catch (Exception e) { } } /** * 提交事务 * @param conn */ public static void commitTransation(Connection conn) { try { if(conn!=null) { if(!conn.getAutoCommit()) { conn.commit(); } } } catch (Exception e) { } } /** * 回滚事务 * @param conn */ public static void rollbackTransation(Connection conn) { try { if(conn!=null) { if(!conn.getAutoCommit()) { conn.rollback(); } } } catch (Exception e) { } } /** * 重启事务 * @param conn */ public static void resetTransation(Connection conn) { try { if(conn!=null) { if(conn.getAutoCommit()) { conn.setAutoCommit(false); }else { conn.setAutoCommit(true); } } } catch (Exception e) { } } } 这样确保了在同一个线程内始终是一个Connection对象,操作事务的前提,在DAO层可以直接从ConnectionManager对象里取出Connection,省去了在方法参数里传递,提高了方法的通用性。 至于什么时候用哪一种思路,还需要具体情况具体分析,并没有一个同一个做法,如果你内存足够大可以用“空间换时间法”倘若内存本来就很小,当然没必要用这种,要不系统都跑不起来。