一年又过去了,习惯上我还是使用阴历来判别一年,元旦过后,我还没有想到一年又过去了,但是过完春节,这种感觉就突然特别强烈起来,呵呵,小时候养成的习惯,不是说变就能改变的。
在一月份怎么说呢,上半个月感觉特别累,人也特别敏感,易怒。下半个月,还是相对比较轻松的心态,就算是犒劳自己吧。第一二周主要是准备工作汇报材料,一群人没日没夜地干,就为了把工作汇报整出色, 还额外新增了许多功能,光说短信吧, 短短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。