帐前卒专栏

code, software architect, articles and novels.
代码,软件架构,博客和小说

其实没有优惠也没有什么关系.但是不能将原价调高一倍,然后对消费者说打五折。淘宝商城是一个很有趣的地方,它让我懂得真正五折优惠是什么含义。
淘宝商城做了下面几件事:
1. 首先打出5折的口号,让大家知道打折。
2. 在快到时间的前十至十五分钟页面禁止购买。这个时候页面链接到的数据库表/块应该还是原来的。
3. 时间一到,切换到新的数据表或者数据块。
当然应该有更简单的策略。例如cache,因为各种宣传要降价的产品其实不多,完全可以使用cache将这些页面缓存起来,因为有十至十五分钟无法购买时间,其实和静
态页面的效果一致。时间已过,页面cache失效,重新读取后台的数据,这时数据已经变了。这种策略只不过加了一张临时表格或者map存储相关数据,对原本的逻辑没有
大改动。推荐时常使用。
技术上咋样都可以,但是不能坑爹。这样大家会骂的…
另外京东就没有啥技术了…买一赠一…买一个电脑赠一个纸箱,买一个电视机赠送一盒塑料泡沫,买一个京东赠一个淘宝。

其实原创一直无法避免抄袭。当然我这篇文章因为很水的缘故,根本不用担心抄袭。

一般来说转载会使用原文的连接。如果博文写得相当的好,非常的动人,肯定有人看到转载的文章会点击原文的连接来看看你。

但前提是相当的好,有深度,有见解,很动人,非功利的技术细节。当然这样的文章基本上是技术水文或者高瞻远瞩的文章,或者谈哲论道的文章。当然对于花心思写的,令人眼
前一亮的文章,图文并茂,还是有人转载。但是很少见人回来再看看博主的。对于转载,一方面方便自己阅读,另一方面又可以供别人阅读,增长下点击率。转载时使用原文链接
,如果是独立博主,其Rank就会日益高涨。但是csdn的博主…当然博主为了传播知识,写文章,传播于众,非常喜欢让别人无署名无链接转载,我觉得也是一件好事
。当然很有可能镜像网站比你更加出名,因为它不仅转载你的,还转载其他人的。

话说回来,是写的快?还是看得快,转的快?

有时候我真觉得知识匮乏。有时查一个关键字,十几篇一样的帖子。完全不适合解决问题,相反倒是增加了不少问题。如果一个原创帖子错了,十几篇跟着错。甚至原创帖改正了
,还是有十几篇错帖。因为转载的帖子可能来自于其他转载过来的帖子。

搜索真的是没有做好,当然据我所知,也做不好。不管是被墙的google,bing, 还是百度,qq。其实有一点不可能做到:机器难分真假。评分和打分机制也不好用
。因为环境的不同,表象虽然一样,适合别人的,却不一定适合自己。而自己满心欢喜写的解决方案,可能对于某些人却是一无是处的垃圾。

搜索引擎到现在为止至少有一件事没有做。我知道google在做去冗余,但是直至今日google依然没有给出这些冗余的不同。或者不冗余的相同。

大家用搜索各有各的用法。我只是用它来找解决方案。当然我也知道,IT民工,永远都只是长尾中的最末端。

很久没有来…想想应该写些什么…更新wiki,的确是不爽的事情,至少应该有个图形编辑界面才行呀。

想想之所以现在写的少了,是因为现在忙了。没有时间去思考,没有时间去总结。忙不是一件好事,总要停下来回头看看得失。突然觉得还是跳槽有意义。师兄从8500的工资
跳到1.5w…这是神马浮云呀…

所以各位要认真学习跳槽的技巧。思考完毕…

花屏错误是因为不兼容导致的。所以需要在运行程序中使用兼容模式。找到在星际争霸1中根文件夹中的所有exe程序,然后对每一个右键->属性->兼容性->使用win98兼容运行,选中256色, 640*480显示两个。然后再运行主exe就ok了。

前几天去了一趟csdn.

看了一下大概一百人左右。开会的空间很大。厕所比我们大厦好得多。

谈了谈合作的事情。猛然间发现貌似没有什么好说的。似乎还是广告,积分,直邮,线下活动。我总觉得应该有些更有创意的事情。其实csdn还能做的更好些。现在下载频道
到处都是广告,虽然不像其他下载站那样都是下载按钮。但是繁杂的广告,让我总感觉不爽。我其实就像找那个大大的下载button,而不是看广告。当然没有广告就赚不了
钱,这谁都知道。

总觉得还应该有创新。结果发现似乎已经穷途末路。或许还应该再找找。

听他们讲合作,讲得我都要睡着了。

还是编码Happy。

1
2
3
4
svn merge is used for merging code from branch or other path to chunk. Or you can use old version to cover new version.
svn co/ svn checkout is commonly used for checking code to local with svn information.
svn import is used for importing code to svn, which has no svn information.
svn export is used for checking out code without svn information.
1
2
3
4
5
svn merge 用于将分支代码迁回到trunk,当然也可以将旧代码覆盖新代码
svn co 这个是最常用的,用于将代码迁到本地
svn import 用于将某些代码或者项目放入到svn server上
svn export 是将代码迁出来,但是迁出来的代码是没有svn信息的

In svn command, if you want rollback your code of svn server. you should use svn merge to merage new version and old version. like :
svn merge -r newversion:oldversion
But if you want check out old version to cover new version. do like this:
svn co -r oldversion svnpath localpath
svn 如果是svn server的代码需要回滚,则使用
1
svn merge -r newversion:oldversion

如果是svn客户端 check out出来的代码需要找到以前的版本,则使用

1
svn co -r version svnpath localpath

javax.mail.MessagingException: A7 NO STORE Can not find message 1;
nested exception is:
com.sun.mail.iap.CommandFailedException: A7 NO STORE Can not find message 1

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at junit.framework.TestCase.runTest(TestCase.java:168)
at junit.framework.TestCase.runBare(TestCase.java:134)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:124)
at junit.framework.TestSuite.runTest(TestSuite.java:232)
at junit.framework.TestSuite.run(TestSuite.java:227)
at
org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:79)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestRe
ference.java:49)
at
org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestR
unner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestR
unner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner
.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunne
r.java:197)
Caused by: javax.mail.MessagingException: A7 NO STORE Can not find message 1;
nested exception is:
com.sun.mail.iap.CommandFailedException: A7 NO STORE Can not find message 1
at com.sun.mail.imap.IMAPMessage.setFlags(IMAPMessage.java:847)
at javax.mail.Message.setFlag(Message.java:565)

… 20 more
Caused by: com.sun.mail.iap.CommandFailedException: A7 NO STORE Can not find
message 1
at com.sun.mail.iap.Protocol.handleResult(Protocol.java:294)
at com.sun.mail.imap.protocol.IMAPProtocol.storeFlags(IMAPProtocol.java:1294)
at com.sun.mail.imap.protocol.IMAPProtocol.storeFlags(IMAPProtocol.java:1279)
at com.sun.mail.imap.IMAPMessage.setFlags(IMAPMessage.java:843)
… 22 more

发现这个是exception是setFlag发出的,在网上查了很久没有找到原因。后来发现是频繁调用setFlag方法导致。原因在于如果一个Message被赋
值为某一个Flag,则不能重复赋值。所以解决办法是首先判断一下。

if (message.isSet(Flags.Flag.DELETED)){
    message.setFlag(Flags.Flag.DELETED);
}

另外删除邮件不管是使用imap还是pop都最好不要使用expunge()方法,这个方法不能保证在所有的mail
server上都成功。都还是message.setFlag()吧,这个最保险。

正确写法:

f.open(Folder.READ_WRITE);
                    for (Message message: f.getMessages()) {
                        if(!message.isSet(Flags.Flag.DELETED))
                        message.setFlag(Flags.Flag.DELETED, true);

                    }
                    f.close(true);

/**

*  转载请注明作者longdick    http://longdick.iteye.com
*

*/

wait()、notify()、notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态。

这三个方法最终调用的都是jvm级的native方法。随着jvm运行平台的不同可能有些许差异。

  • 如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。
  • 如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。
  • 如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。

其中wait方法有三个over load方法:

wait()

wait(long)

wait(long,int)

wait方法通过参数可以指定等待的时长。如果没有指定参数,默认一直等待直到被通知。

以下是一个演示代码,以最简洁的方式说明复杂的问题:

简要说明下:

NotifyThread是用来模拟3秒钟后通知其他等待状态的线程的线程类;

WaitThread是用来模拟等待的线程类;

等待的中间对象是flag,一个String对象;

main方法中同时启动一个Notify线程和三个wait线程;

public class NotifyTest {
	private  String flag = "true";

	class NotifyThread extends Thread{
		public NotifyThread(String name) {
			super(name);
		}
		public void run() {		
			try {
				sleep(3000);//推迟3秒钟通知
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
				flag = "false";
				flag.notify();
		}
	};

	class WaitThread extends Thread {
		public WaitThread(String name) {
			super(name);
		}

		public void run() {
			
				while (flag!="false") {
					System.out.println(getName() + " begin waiting!");
					long waitTime = System.currentTimeMillis();
					try {
						flag.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					waitTime = System.currentTimeMillis() - waitTime;
					System.out.println("wait time :"+waitTime);
				}
				System.out.println(getName() + " end waiting!");
			
		}
	}

	public static void main(String[] args) throws InterruptedException {
		System.out.println("Main Thread Run!");
		NotifyTest test = new NotifyTest();
		NotifyThread notifyThread =test.new NotifyThread("notify01");
		WaitThread waitThread01 = test.new WaitThread("waiter01");
		WaitThread waitThread02 = test.new WaitThread("waiter02");
		WaitThread waitThread03 = test.new WaitThread("waiter03");
		notifyThread.start();
		waitThread01.start();
		waitThread02.start();
		waitThread03.start();
	}

}

OK,如果你拿这段程序去运行下的话, 会发现根本运行不了,what
happened?满屏的java.lang.IllegalMonitorStateException。

没错,这段程序有很多问题,我们一个个来看。

首先,这儿要非常注意的几个事实是

  1. 任何一个时刻,对象的控制权(monitor)只能被一个线程拥有。
  2. 无论是执行对象的wait、notify还是notifyAll方法,必须保证当前运行的线程取得了该对象的控制权(monitor)
  3. 如果在没有控制权的线程里执行对象的以上三种方法,就会报java.lang.IllegalMonitorStateException异常。
  4. JVM基于多线程,默认情况下不能保证运行时线程的时序性

基于以上几点事实,我们需要确保让线程拥有对象的控制权。

也就是说在waitThread中执行wait方法时,要保证waitThread对flag有控制权;

在notifyThread中执行notify方法时,要保证notifyThread对flag有控制权。

线程取得控制权的方法有三:

  1. 执行对象的某个同步实例方法。
  2. 执行对象对应类的同步静态方法。
  3. 执行对该对象加同步锁的同步块。

我们用第三种方法来做说明:

将以上notify和wait方法包在同步块中

synchronized (flag) {
				flag = "false";
				flag.notify();
			}
synchronized (flag) {
				while (flag!="false") {
					System.out.println(getName() + " begin waiting!");
					long waitTime = System.currentTimeMillis();
					try {
						flag.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					waitTime = System.currentTimeMillis() - waitTime;
					System.out.println("wait time :"+waitTime);
				}
				System.out.println(getName() + " end waiting!");
			}

我们向前进了一步。

问题解决了吗?

好像运行还是报错java.lang.IllegalMonitorStateException。what happened?

这时的异常是由于在针对flag对象同步块中,更改了flag对象的状态所导致的。如下:

flag=“false”;

flag.notify();

对在同步块中对flag进行了赋值操作,使得flag引用的对象改变,这时候再调用notify方法时,因为没有控制权所以抛出异常。

我们可以改进一下,将flag改成一个JavaBean,然后更改它的属性不会影响到flag的引用。

我们这里改成数组来试试,也可以达到同样的效果:

private   String flag[] = {"true"};
	synchronized (flag) {
				flag[0] = "false";
				flag.notify();
			}
synchronized (flag) {
				flag[0] = "false";
				flag.notify();
			}synchronized (flag) {
				while (flag[0]!="false") {
					System.out.println(getName() + " begin waiting!");
					long waitTime = System.currentTimeMillis();
					try {
						flag.wait();
						
					} catch (InterruptedException e) {
						e.printStackTrace();
					}

这时候再运行,不再报异常,但是线程没有结束是吧,没错,还有线程堵塞,处于wait状态。

原因很简单,我们有三个wait线程,只有一个notify线程,notify线程运行notify方法的时候,是随机通知一个正在等待的线程,所以,现在应该还有两
个线程在waiting。

我们只需要将NotifyThread线程类中的flag.notify()方法改成notifyAll()就可以了。notifyAll方法会通知所有正在等待对象
控制权的线程。

最终完成版如下:

public class NotifyTest {
	private String flag[] = { "true" };

	class NotifyThread extends Thread {
		public NotifyThread(String name) {
			super(name);
		}

		public void run() {
			try {
				sleep(3000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			synchronized (flag) {
				flag[0] = "false";
				flag.notifyAll();
			}
		}
	};

	class WaitThread extends Thread {
		public WaitThread(String name) {
			super(name);
		}

		public void run() {
			synchronized (flag) {
				while (flag[0] != "false") {
					System.out.println(getName() + " begin waiting!");
					long waitTime = System.currentTimeMillis();
					try {
						flag.wait();

					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					waitTime = System.currentTimeMillis() - waitTime;
					System.out.println("wait time :" + waitTime);
				}
				System.out.println(getName() + " end waiting!");
			}
		}
	}

	public static void main(String[] args) throws InterruptedException {
		System.out.println("Main Thread Run!");
		NotifyTest test = new NotifyTest();
		NotifyThread notifyThread = test.new NotifyThread("notify01");
		WaitThread waitThread01 = test.new WaitThread("waiter01");
		WaitThread waitThread02 = test.new WaitThread("waiter02");
		WaitThread waitThread03 = test.new WaitThread("waiter03");
		notifyThread.start();
		waitThread01.start();
		waitThread02.start();
		waitThread03.start();
	}

}

Yesteday, I have tried many methods to rewrite HTML. And find TagNode can not write TextNode, so if I want to replace "<p> id="hello"></p>" to "<p id="hello">it's me</p>". There is no method to support. And in htmlParser, there is a method call setText(). But setText is only set text into<p id="hello">, like "<p id="hello" class="pp">". The method can not write text into"<p></p>". If you want to add a TextNode as TagNode child. HtmlParser can not support this idea also. Like:

NodeList nl = p.parse(null);
NodeVisitor nv = new NodeVisitor(){
public void visitTag(Tag tag) {
if (tag instanceof ParagraphTag) {
String attribute = tag.getAttribute(“id”);
if (attribute == null){
return;
}
TextNode tn = new TextNode(tag.getText());
tn.setText("sidafnaf ");
if(tag.getAttribute(“id”).equals(“hello”)){
Text t = new TextNode(“abc”);
t.setParent(tag);
// It does not work
NodeList temp = new NodeList();
temp.add(t);
tag.setChildren(temp);
} else if (tag.getAttribute(“id”).equals(“author”)){
tag.setAttribute(“innerHTML”,“id a”);
}
} else if (tag instanceof LinkTag){
if (tag.getAttribute(“id”).equals(“come-from”)){
// can write an attribute innerHtml = “ok?”
tag.setAttribute(“innerHtml”,“ok?”);
// can rewrite URL attribute
tag.setAttribute(“href”, “http://www.google.com”);
}
}
}
};

Solve this problem, you should flag where you want to insert. like<p>messgae</p>
Then use following code:

NodeList nl = p.parse(null);
NodeVisitor nv = new NodeVisitor(){
public void visitStringNode(Text string){
if(string.getText().equals(“message”)){
string.setText(“It’s me”);
}
// if you want change attributes of <p>
TagNode tn = string.getParent();
tn.setAttribute(“id”,“good!”);
}
}

Now it’s done.

0%