一年又過去了,習慣上我還是使用陰歷來判別一年,元旦過后,我還沒有想到一年又過去了,但是過完春節,這種感覺就突然特別強烈起來,呵呵,小時候養成的習慣,不是說變就能改變的。
在一月份怎么說呢,上半個月感覺特別累,人也特別敏感,易怒。下半個月,還是相對比較輕松的心態,就算是犒勞自己吧。第一二周主要是準備工作匯報材料,一群人沒日沒夜地干,就為了把工作匯報整出色, 還額外新增了許多功能,光說短信吧, 短短3天,就集成進了系統,這個不容易啊,每個人都鉚足了勁,想整點色彩出來,當然我其實也知道,我說過12月會輕松一點,但是12月份沒有輕松過,然后我又說1月份會輕松一點,接著就是更累得一月份,自己也感覺慚愧啊,項目本來工作量太多是一方面,但是更多的,我還是認為,管理上面還是存在很大問題,沒有預見到兩個重大問題,第一,框架的嚴重不足,第二,人員培訓嚴重不足,當時對框架依賴程度過高, 其實框架在后面幾次致命的變動,給系統帶來的修改工作量非同一般啊;對人員的水平估計過高,也是把所有人包括自己弄得很慘的一個重要原因,以為經過前面的一個小項目,人員水平應該都有很大的提高,滿足一般的項目需求問題不是很大的,但是實際情況告訴我,從一個不懂編程到熟練工, 絕對不是一蹴而就的,就算是勞動強度很大的鍛煉,那也需要很長時間的,至少也需要一到兩年。我們只用了2個月,就算是學了九陽神功也沒有那么快啊。當然所有的一切責任歸結起來,就是項目管理的失敗,風險識別錯誤,一開始的風險識別就只是考慮時間緊,業務不熟練,根本就沒有考慮到人員的技術水平,所以后面對質量的忽視的默許,對人員培養的中斷, 直接導致了最后的一個大泥潭,當然我們現在是甲方,這個跳蚤還是得自己摘掉的,因為你不是干一票就走人的阿。
在匯報后,就開始進行年終總結, 呵呵,因為有很多感想,計劃的三千字,輕易的就達到,寫得時候根本就沒有考慮過達到了。
針對需要改進的內容也寫了很多,有幾點特別重要,第一,千萬不要深度參與到項目的開發中去,因為這樣你害了所有人,沒有統籌安排,必然導致更多的問題和混亂,而且這些內容遲早要交接出去的,那么,別人接手還是很痛苦,所以從一開始就要把握好自己。第二,計劃很重要,計劃要仔細考慮,不是一拍腦袋,計劃就出來,完成了很多電子表格,但是這沒有用,有用的計劃應該是討論出來的,是仔細思考,全盤考慮的結果。最后,計劃始終只是計劃,還需要不斷跟進,這樣才能逐步逼近目標。
下月還有一些計劃,主要一個是制定項目管理規范,很多時候做到有章可循還是比較好的,最佳實踐不一定完全適合你,但是你總能受點啟發吧。日積月累,不就形成了一個所以得經驗了嗎?打游戲還講究經驗值呢,做事為什么就要拒絕經驗呢。
第二個,還要把現在的內容消化,現在內容很多,但老實說,需要花力氣整合,而且還有些核心功能都不是特別穩定,也急切需要穩定。現在一堆所謂的重構, 但是我一直知道有一句話,沒有最好,只有最合適。其實對于軟件也是這樣,優化是沒有止境的,但是我們也要有一個度,再過三個月,回過頭來看,現在的很多功能和代碼又會有點像狗屎,因為你進步了。是不是我們再花力氣把它們都重構一下呢,不一定。首先用戶對于你的修改是否認為一定需要,用的還蠻好的,也總的給我一個更換的理由吧, 總不能說廠家都從n70換到n73, 我就要換吧。其次,你的時間和精力允許你這樣做嗎?但是并不是代表我們就什么都不做,一直拒絕新事物,這樣怎么能從量變到質變呢,不質變,不適應新情況了總是要被淘汰的吧,比如小靈通。
所以我想我們每個人都要習慣改變,但是要抓住本質,有一句話“要么改變,要么被改變”。
1, 使用java提供的方法,在jsp或者servlet中都可以
<%
response.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires", 0);
%>
2, 使用HTML標記,如下面:
<HEAD>
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" CONTENT="0">
</HEAD>
轉載
http://www.matrix.org.cn/thread.shtml?forum_id=19&view_id=919int、char、double與byte相互轉換的程序
//整數到字節數組的轉換
public static byte[] intToByte(int number) {
int temp = number;
byte[] b=new byte[4];
for (int i=b.length-1;i>-1;i--){
b[i] = new Integer(temp&0xff).byteValue(); //將最高位保存在最低位
temp = temp >> 8; //向右移8位
}
return b;
}
//字節數組到整數的轉換
public static int byteToInt(byte[] b) {
int s = 0;
for (int i = 0; i < 3; i++) {
if (b[i] >= 0)
s = s + b[i];
else
s = s + 256 + b[i];
s = s * 256;
}
if (b[3] >= 0) //最后一個之所以不乘,是因為可能會溢出
s = s + b[3];
else
s = s + 256 + b[3];
return s;
}
//字符到字節轉換
public static byte[] charToByte(char ch){
int temp=(int)ch;
byte[] b=new byte[2];
for (int i=b.length-1;i>-1;i--){
b[i] = new Integer(temp&0xff).byteValue(); //將最高位保存在最低位
temp = temp >> 8; //向右移8位
}
return b;
}
//字節到字符轉換
public static char byteToChar(byte[] b){
int s=0;
if(b[0]>0)
s+=b[0];
else
s+=256+b[0];
s*=256;
if(b[1]>0)
s+=b[1];
else
s+=256+b[1];
char ch=(char)s;
return ch;
}
//浮點到字節轉換
public static byte[] doubleToByte(double d){
byte[] b=new byte[8];
long l=Double.doubleToLongBits(d);
for(int i=0;i<b.length;i++){
b[i]=new Long(l).byteValue();
l=l>>8;
}
return b;
}
//字節到浮點轉換
public static double byteToDouble(byte[] b){
long l;
l=b[0];
l&=0xff;
l|=((long)b[1]<<8);
l&=0xffff;
l|=((long)b[2]<<16);
l&=0xffffff;
l|=((long)b[3]<<24);
l&=0xffffffffl;
l|=((long)b[4]<<32);
l&=0xffffffffffl;
l|=((long)b[5]<<40);
l&=0xffffffffffffl;
l|=((long)b[6]<<48);
l|=((long)b[7]<<56);
return Double.longBitsToDouble(l);
}
--
先從線程的創建說起.線程的創建一共有兩種形式:
--------------------------------------------------------------------------------
一種是繼承自Thread類.Thread 類是一個具體的類,即不是抽象類,該類封裝了線程的行為.要創建一個線程,程序員必須創建一個從 Thread 類導出的新類.程序員通過覆蓋 Thread 的 run() 函數來完成有用的工作.用戶并不直接調用此函數;而是通過調用 Thread 的 start() 函數,該函數再調用 run(). 例如:
public class Test extends Thread{ public Test(){ } public static void main(String args[]){ Test t1 = new Test(); Test t2 = new Test(); t1.start(); t2.start(); } public void run(){ //do thread's things } }
--------------------------------------------------------------------------------
另一種是實現Runnable接口,此接口只有一個函數,run(),此函數必須由實現了此接口的類實現. 例如:
public class Test implements Runnable{ Thread thread1; Thread thread2; public Test(){ thread1 = new Thread(this,"1"); thread2 = new Thread(this,"2"); } public static void main(String args[]){ Test t = new Test(); t.startThreads(); } public void run(){ //do thread's things } public void startThreads(){ thread1.start(); thread2.start(); } }
兩種創建方式看起來差別不大,但是弄不清楚的話,也許會將你的程序弄得一團糟.兩者區別有以下幾點:
1.當你想繼承某一其它類時,你只能用后一種方式.
2.第一種因為繼承自Thread,只創建了自身對象,但是在數量上,需要幾個線程,就得創建幾個自身對象;第二種只創建一個自身對象,卻創建幾個Thread對象.而兩種方法重大的區別就在于此,請你考慮:如果你在第一種里創建數個自身對象并且start()后,你會發現好像synchronized不起作用了,已經加鎖的代碼塊或者方法居然同時可以有幾個線程進去,而且同樣一個變量,居然可以有好幾個線程同時可以去更改它.(例如下面的代碼)這是因為,在這個程序中,雖然你起了數個線程,可是你也創建了數個對象,而且,每個線程對應了每個對象也就是說,每個線程更改和占有的對象都不一樣,所以就出現了同時有幾個線程進入一個方法的現象,其實,那也不是一個方法,而是不同對象的相同的方法.所以,這時候你要加鎖的話,只能將方法或者變量聲明為靜態,將static加上后,你就會發現,線程又能管住方法了,同時不可能有兩個線程進入同樣一個方法,那是因為,現在不是每個對象都擁有一個方法了,而是所有的對象共同擁有一個方法,這個方法就是靜態方法.
而你如果用第二種方法使用線程的話,就不會有上述的情況,因為此時,你只創建了一個自身對象,所以,自身對象的屬性和方法對于線程來說是共有的.
因此,我建議,最好用后一種方法來使用線程.
public class mainThread extends Thread{ int i=0; public static void main(String args[]){ mainThread m1 = new mainThread(); mainThread m2 = new mainThread(); mainThread m3 = new mainThread(); mainThread m4 = new mainThread(); mainThread m5 = new mainThread(); mainThread m6 = new mainThread(); m1.start(); m2.start(); m3.start(); m4.start(); m5.start(); m6.start(); } public synchronized void t1(){ i=++i; try{
|
Thread.sleep(500);
}
catch(Exception e){}
//每個線程都進入各自的t1()方法,分別打印各自的i
System.out.println(Thread.currentThread().getName()+" "+i);
}
public void run(){
synchronized(this){
while (true) {
t1();
}
}
}
}
--------------------------------------------------------------------------------
下面我們來講synchronized的4種用法吧:
1.方法聲明時使用,放在范圍操作符(public等)之后,返回類型聲明(void等)之前.即一次只能有一個線程進入該方法,其他線程要想在此時調用該方法,只能排隊等候,當前線程(就是在synchronized方法內部的線程)執行完該方法后,別的線程才能進入.
例如:
public synchronized void synMethod() {
//方法體
}
2.對某一代碼塊使用,synchronized后跟括號,括號里是變量,這樣,一次只有一個線程進入該代碼塊.例如:
public int synMethod(int a1){
synchronized(a1) {
//一次只能有一個線程進入
}
}
3.synchronized后面括號里是一對象,此時,線程獲得的是對象鎖.例如:
public class MyThread implements Runnable {
public static void main(String args[]) {
MyThread mt = new MyThread();
Thread t1 = new Thread(mt, "t1");
Thread t2 = new Thread(mt, "t2");
Thread t3 = new Thread(mt, "t3");
Thread t4 = new Thread(mt, "t4");
Thread t5 = new Thread(mt, "t5");
Thread t6 = new Thread(mt, "t6");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
public void run() {
synchronized (this) {
System.out.println(Thread.currentThread().getName());
}
}
}
對于3,如果線程進入,則得到對象鎖,那么別的線程在該類所有對象上的任何操作都不能進行.在對象級使用鎖通常是一種比較粗糙的方法.為什么要將整個對象都上鎖,而不允許其他線程短暫地使用對象中其他同步方法來訪問共享資源?如果一個對象擁有多個資源,就不需要只為了讓一個線程使用其中一部分資源,就將所有線程都鎖在外面.由于每個對象都有鎖,可以如下所示使用虛擬對象來上鎖:
class FineGrainLock {
MyMemberClass x, y;
Object xlock = new Object(), ylock = new Object();
public void foo() {
synchronized(xlock) {
//access x here
}
//do something here - but don't use shared resources
synchronized(ylock) {
//access y here
}
}
public void bar() {
synchronized(this) {
//access both x and y here
}
//do something here - but don't use shared resources
}
}
4.synchronized后面括號里是類.例如:
class ArrayWithLockOrder{
private static long num_locks = 0;
private long lock_order;
private int[] arr;
public ArrayWithLockOrder(int[] a)
{
arr = a;
synchronized(ArrayWithLockOrder.class) {//-----------------------------------------這里
num_locks++; // 鎖數加 1.
lock_order = num_locks; // 為此對象實例設置唯一的 lock_order.
}
}
public long lockOrder()
{
return lock_order;
}
public int[] array()
{
return arr;
}
}
class SomeClass implements Runnable
{
public int sumArrays(ArrayWithLockOrder a1,
ArrayWithLockOrder a2)
{
int value = 0;
ArrayWithLockOrder first = a1; // 保留數組引用的一個
ArrayWithLockOrder last = a2; // 本地副本.
int size = a1.array().length;
if (size == a2.array().length)
{
if (a1.lockOrder() > a2.lockOrder()) // 確定并設置對象的鎖定
{ // 順序.
first = a2;
last = a1;
}
synchronized(first) { // 按正確的順序鎖定對象.
synchronized(last) {
int[] arr1 = a1.array();
int[] arr2 = a2.array();
for (int i=0; i<size; i++)
value += arr1[i] + arr2[i];
}
}
}
return value;
}
public void run() {
//...
}
}
對于4,如果線程進入,則線程在該類中所有操作不能進行,包括靜態變量和靜態方法,實際上,對于含有靜態方法和靜態變量的代碼塊的同步,我們通常用4來加鎖.
以上4種之間的關系:
鎖是和對象相關聯的,每個對象有一把鎖,為了執行synchronized語句,線程必須能夠獲得synchronized語句中表達式指定的對象的鎖,一個對象只有一把鎖,被一個線程獲得之后它就不再擁有這把鎖,線程在執行完synchronized語句后,將獲得鎖交還給對象.
在方法前面加上synchronized修飾符即可以將一個方法聲明為同步化方法.同步化方法在執行之前獲得一個鎖.如果這是一個類方法,那么獲得的鎖是和聲明方法的類相關的Class類對象的鎖.如果這是一個實例方法,那么此鎖是this對象的鎖.
--------------------------------------------------------------------------------
下面談一談一些常用的方法:
wait(),wait(long),notify(),notifyAll()等方法是當前類的實例方法,
wait()是使持有對象鎖的線程釋放鎖;
wait(long)是使持有對象鎖的線程釋放鎖時間為long(毫秒)后,再次獲得鎖,wait()和wait(0)等價;
notify()是喚醒一個正在等待該對象鎖的線程,如果等待的線程不止一個,那么被喚醒的線程由jvm確定;
notifyAll是喚醒所有正在等待該對象鎖的線程.
在這里我也重申一下,我們應該優先使用notifyAll()方法,因為喚醒所有線程比喚醒一個線程更容易讓jvm找到最適合被喚醒的線程.
對于上述方法,只有在當前線程中才能使用,否則報運行時錯誤java.lang.IllegalMonitorStateException: current thread not owner.
--------------------------------------------------------------------------------
下面,我談一下synchronized和wait(),notify()等的關系:
1.有synchronized的地方不一定有wait,notify
2.有wait,notify的地方必有synchronized.這是因為wait和notify不是屬于線程類,而是每一個對象都具有的方法,而且,這兩個方法都和對象鎖有關,有鎖的地方,必有synchronized.
另外,請注意一點:如果要把notify和wait方法放在一起用的話,必須先調用notify后調用wait,因為如果調用完wait,該線程就已經不是current thread了.如下例:
/**
* Title: Jdeveloper's Java Projdect
* Description: n/a
* Copyright: Copyright ? 2001
* Company: soho http://www.ChinaJavaWorld.com
* @author jdeveloper@21cn.com
* @version 1.0
*/
import java.lang.Runnable;
import java.lang.Thread;
public class DemoThread
implements Runnable {
public DemoThread() {
TestThread testthread1 = new TestThread(this, "1");
TestThread testthread2 = new TestThread(this, "2");
testthread2.start();
testthread1.start();
}
public static void main(String[] args) {
DemoThread demoThread1 = new DemoThread();
}
public void run() {
TestThread t = (TestThread) Thread.currentThread();
try {
if (!t.getName().equalsIgnoreCase("1")) {
synchronized (this) {
wait();
}
}
while (true) {
System.out.println("@time in thread" + t.getName() + "=" +
t.increaseTime());
if (t.getTime() % 10 == 0) {
synchronized (this) {
System.out.println("****************************************");
notify();
if (t.getTime() == 100)
break;
wait();
}
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}
class TestThread
extends Thread {
private int time = 0;
public TestThread(Runnable r, String name) {
super(r, name);
}
public int getTime() {
return time;
}
public int increaseTime() {
return++time;
}
}
下面我們用生產者/消費者這個例子來說明他們之間的關系:
public class test {
public static void main(String args[]) {
Semaphore s = new Semaphore(1);
Thread t1 = new Thread(s, "producer1");
Thread t2 = new Thread(s, "producer2");
Thread t3 = new Thread(s, "producer3");
Thread t4 = new Thread(s, "consumer1");
Thread t5 = new Thread(s, "consumer2");
Thread t6 = new Thread(s, "consumer3");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}
class Semaphore
implements Runnable {
private int count;
public Semaphore(int n) {
this.count = n;
}
public synchronized void acquire() {
while (count == 0) {
try {
wait();
}
catch (InterruptedException e) {
//keep trying
}
}
count--;
}
public synchronized void release() {
while (count == 10) {
try {
wait();
}
catch (InterruptedException e) {
//keep trying
}
}
count++;
notifyAll(); //alert a thread that's blocking on this semaphore
}
public void run() {
while (true) {
if (Thread.currentThread().getName().substring(0,8).equalsIgnoreCase("consumer")) {
acquire();
}
else if (Thread.currentThread().getName().substring(0,8).equalsIgnoreCase("producer")) {
release();
}
System.out.println(Thread.currentThread().getName() + " " + count);
}
}
}
生產者生產,消費者消費,一般沒有沖突,但當庫存為0時,消費者要消費是不行的,但當庫存為上限(這里是10)時,生產者也不能生產.請好好研讀上面的程序,你一定會比以前進步很多.
上面的代碼說明了synchronized和wait,notify沒有絕對的關系,在synchronized聲明的方法,代碼塊中,你完全可以不用wait,notify等方法,但是,如果當線程對某一資源存在某種爭用的情況下,你必須適時得將線程放入等待或者喚醒.
------------------------
在java中,每個對象只有一個相應的monitor,一個mutex,而每一個monitor都可以有多個“doors”可以進入,即,同一個monitor中被守護的代碼可以在不同的地方,因為同一個對象可以出現在不同的代碼段,只要mutex鎖定的對象是同一個,每個入口都用Synchronized關鍵字表明,當一個線程通過了Synchronized關鍵字,它就所住了該monitor所有的doors。因此是mutex定義了monitor而不是代碼。
另外,wait和notify、notifyAll都是Object的方法,使用wait必須是The current thread must own this object's monitor
wait
public final void wait()
throws InterruptedExceptionCauses current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0).
The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.
This method should only be called by a thread that is the owner of this object's monitor. See the notify method for a description of the ways in which a thread can become the owner of a monitor.
Throws:
IllegalMonitorStateException - if the current thread is not the owner of the object's monitor.
InterruptedException - if another thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown.
See Also:
notify(), notifyAll()
A thread becomes the owner of the object's monitor in one of three ways:
By executing a synchronized instance method of that object.
By executing the body of a synchronized statement that synchronizes on the object.
For objects of type Class, by executing a synchronized static method of that class.
Only one thread at a time can own an object's monitor.
vc6.0 使用ado存取mysql5.0 的decimal類型的時候有問題。
在多線程中使用CSocket的時候要注意了,必須是從CWndThread派生的UI Thread。