转载自一篇经典的终结,忘记出处了……百看不厌
synchronized(obj) {
while(!condition) {
obj.wait();
}
obj.doSomething();
}
当线程A获得了obj锁后,发现条件condition不满足,无法继续下一处理,于是线程A就wait() , 放弃对象锁.
之后在另一线程B中,如果B更改了某些条件,使得线程A的condition条件满足了,就可以唤醒线程A:
synchronized(obj) {
condition = true;
obj.notify();
}
需要注意的概念是:
# 调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj) {…} 代码段内。
# 调用obj.wait()后,线程A就释放了obj的锁,否则线程B无法获得obj锁,也就无法在synchronized(obj) {…} 代码段内唤醒A。
# 当obj.wait()方法返回后,线程A需要再次获得obj锁,才能继续执行。
# 如果A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个(具体哪一个由JVM决定)。
# obj.notifyAll()则能全部唤醒A1,A2,A3,但是要继续执行obj.wait()的下一条语句,必须获得obj锁,因此,A1,A2,A3只有一个有机会获得锁继续执行,例如A1,其余的需要等待A1释放obj锁之后才能继续执行。
# 当B调用obj.notify/notifyAll的时候,B正持有obj锁,因此,A1,A2,A3虽被唤醒,但是仍无法获得obj锁。直到B退出synchronized块,释放obj锁后,A1,A2,A3中的一个才有机会获得锁继续执行。
java基础
notify, synchronized, wait, 对象锁
非常常用的一个算法就是,a和b的交换,我们总是用到一个中间变量来进行交换。
其实可以用异或符来计算,这样就不会花销额外空间了,因为异或是可逆的。
比如a^b=c c^b=a 所以a可以通过可逆计算,算回来的。
a和b的交换:
a = a^b
b = b^a 此时的b就相当于被异或回来的a
a = a^b 这里的思路要转一转,我们可以想成,相当于是 a = (a^b)^a = (b^a)^a = b(注意!这里的a和b都是原始的)
java基础
交换, 额外空间
首先建立矩阵图,让我们可以针对不同的数字,取不同的字符,如果要输入10的16进制,只需要digits[10],这样就可以将数字与字符对应起来:
- final static char[] digits = {
- ‘0‘ , ‘1‘ , ‘2‘ , ‘3‘ , ‘4‘ , ‘5‘ ,
- ‘6‘ , ‘7‘ , ‘8‘ , ‘9‘ , ‘a‘ , ‘b‘ ,
- ‘c‘ , ‘d‘ , ‘e‘ , ‘f‘
- };
接下来的思路是,任意举一个数字,然后将它在草稿纸上写成二进制
0100111010111100101
我们按照3位3位的划分开来(准备8进制的取法),之后每3位取其值,就是8进制的表示了。
0 100 111 010 111 100 101
0 4 7 2 7 4 5
我们按照4位4位的划分,之后每4位取其值,就是16进制的表示了。
010 0111 0101 1110 0101
2 7 5 E 5
我们现在要做的就是要用一个掩码,去取我们要取的数字,比如以16进制为例,先用掩码0000000 1111和我们的数字去做与操作,得出的就是5,之后让我们的数字右移4位(用>>>操作符),再用掩码做与操作,得出E,依次循环。算法如下:
- private static String toUnsignedString(int i, int shift) {//shift就是移的位数,二进制1,8进制3,16进制4
- char[] buf = new char[32];
- int charPos = 32;
- int radix = 1 << shift;
- int mask = radix - 1;
- do {
- buf[--charPos] = digits[i & mask];
- i >>>= shift;
- } while (i != 0);
-
- return new String(buf, charPos, (32 - charPos));
- }
上面是对于int算法,其他数据类型也一样
float 4 字节 32位IEEE 754单精度
double 8 字节 64位IEEE 754双精度
byte 1字节 -128到127
short 2 字节 -32,768到32,767
int 4 字节 -2,147,483,648到2,147,483,647
long 8 字节 -9,223,372,036,854,775,808到9,223,372,036, 854,775,807
char 2 字节 整个Unicode字符集
boolean 1 位 True或者false
另外需要补充的基础知识是负数的二进制形式
计算机中的负数是以补码形式来存放的,出发点是计算机中没有减法,只有加法,那么如何让一个正数与一个负数去相加呢? 我们举个例子:8+(-6)= (8 + (10-6))%10 = 2
这里我们先对-6进行一个转换,让它和模相加,取出一个4,让4和8去加,然后取模,得出2.(这里的模是10)。
18-9 = (18 + 91)%100 = 9
780-50 = (780+950)%1000 = 730
这其中的规律,相信大家一定可以猜到了。
同样,计算机中的负数,也是这么表示的,比如-1,就是11111111111111111111111111111111,一旦与1去相加,刚好进位到溢出为止,得到全部的0.
java基础
16进制, 二进制, 八进制, 字符串