步,
(对两个方法或者更多进行同步)),现在有多个茅坑(print(String name),print2(String name)),只有一个钥匙(同步监视器),那么当一个人(Thread)进去后,拿了那仅有的一个钥匙,就算其他人(Thread)想进入的没有人占的茅坑也不行,因为没有钥匙.
这样的话,打印name的时候就不会出现问题.
现在还有一种情况:
[java]
//静态的同步方法同样也有同步监视器,它是class
public static synchronized void print3(String name) {
for (int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
System.out.println();// 打印完字符串换行
}
这样的话要想互斥就必须把同步监视器改成Outputer.class了,在内存中只有一份.
线程之间的同步通信
通过一道面试提来解释.
子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序。
[java]
//静态的同步方法同样也有同步监视器,它是class
public static synchronized void print3(String name) {
for (int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
System.out.println();// 打印完字符串换行
}
这样的话要想互斥就必须把同步监视器改成Outputer.class了,在内存中只有一份.
线程之间的同步通信
通过一道面试提来解释.
子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序。
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
for (int k = 1; k <= 50; k++) {
for (int i = 1; i <= 10; i++) {
System.out.println("sub thread sequence " + i
+ " loop of " + k);
}
}
}
}).start();
for (int k = 1; k <= 50; k++) {
for (int i = 1; i <= 100; i++) {
System.out
.println("main thread sequence " + i + " loop of " + k);
}
}
}
这样主要的程序逻辑是实现了,但是执行的次序乱来,子线程执行10次不应该别打断,主线程执行100次也不应该被打断.
所以我们自然就想到了同步,只需要把子循环使用同步代码块,但是用什么作为同步监视器呢 this显然不行的.当然该类的字节码class是可以的,但是这样有2个问题,
第一,虽然实现了同步,但是,不是子线程一次,主线程一次,所以在子/主(线程)次序上还是乱了.
第二,使用class作为同步监视器不好,如果程序逻辑很复杂,需要多组需要互斥,使用class作为同步监视器,那么就成了一组了.所以这也不好.
经验:要用到共同数据(包括同步锁)或共同算法的若干个方法,应该归在同一个类上,这种设计体现了高内聚和程序的健壮性.
比如:
据此,我们可以这样设计
class Business {
publicsynchronizedvoid sub(int k) {
for (int i = 1; i <= 10; i++) {
System.out.println("sub thread sequence " + i +" loop of " + k);
}
}
publicsynchronizedvoid main(int k) {
for (int i = 1; i <= 100; i++) {
System.out.println("main thread sequence " + i +" loop of " + k);
}
}
}
这样就把相关的方法写到一个类里面了.但是这里还是没有解决通信问题. 最终代码如下:
publicstaticvoid main(String[] args) {
final Business business =new Business();
new Thread(new Runnable() {
@Override
publicvoid run() {
for (int k = 1; k <= 50; k++) {
business.sub(k);
}
}
}).start();
for (int k = 1; k <= 50; k++) {
business.main(k);
}
}
}
class Business {
//默认子线程先执行
booleanisShouldSub =true;
publicsynchronizedvoid sub(int k) {
if(!isShouldSub){//此处用while最好,因为可能出现假唤醒,//用while的话还会重新判断,这样程序更加严谨和健壮
try {
this.wait();//this表示同步监视器对象
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int i = 1; i <= 10; i++) {
System.out.println("sub thread sequence " + i +" loop of " + k);
}
//子线程做完了,把它置为false
isShouldSub =false;
//并且唤醒主线程
this.notify();
}
publicsynchronizedvoid main(int k) {
if(isShouldSub){){//此处用while最好,因为可能出现假唤醒(API文档里有介绍),//用while的话还会重新判断,这样程序更加严谨和健壮
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int i = 1; i <= 100; i++) {
System.out.println("main thread sequence " + i +" loop of " + k);
}
//主线程做完了,把它置为true
isShouldSub =true;
//并且唤醒子线程
this.notify();
}
}
4,线程范围内共享数据.(ThreadLocal)
下面通过一个简单的示例来描述线程之间非共享数据.
[java]
private static int k = 0;
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
@Override
public void run() {