很多同窗在学习Java中的多线程这一章时,都会以为脑子很乱,以为这一章的知识点太难以理解。特别是对于其中线程同步(synchronized)更是迷茫。本文试图以浅显的例子来跟你们共同分享学习心得。 java
先看一个例子 多线程
package com.chinasofti.thread; 学习
publicclass MyThread implements Runnable{ 测试
privateinta = 1; spa
publicsynchronizedvoid f1(){ 线程
System.out.println("a = " + a); 对象
try { 接口
Thread.sleep(1000); 同步
} catch (InterruptedException e) { io
// TODO Auto-generated
catch block
e.printStackTrace();
}
System.out.println("a = " + a);
}
publicvoid f2(){
a++;
}
publicvoid run() {
f1();
}
publicstaticvoid main(String[] args) {
MyThread myThread = newMyThread();
Thread t1 = newThread(myThread);
t1.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated
catch block
e.printStackTrace();
}
myThread.f2();
}
}
例子说明:咱们自定义了一个MyThread类,该类实现了java.lang.Runnable接口。类中包含一个静态私有变量a=1;提供了一个同步方法f1,该方法的做用是先打印a,而后执行该方法的线程休眠1000毫秒,再次打印a;提供了一个非同步方法f2,该方法做用是使a自加1;实现java.lang.Runnable接口的run方法,该方法执行f1()。
程序启动时,首先启动主线程执行main方法。在main方法中,先new一个MyThread类对象myThread,再利用该对象建立一条线程t1,调用其start()方法启动线程,主线程休眠100毫秒的做用是使得t1在主线程休眠期间获得CPU执行权,执行到f1()方法中的Thread.sleep(1000)处。在t1线程休眠1000毫秒时,主线程继续执行MyThread.f2()。该测试程序的最终结果是打印a=1 a=2。也就是说在t1线程执行同步方法f1并休眠1000毫秒的空当里,主线程执行了myThread对象的非同步方法f2(),修改了a的值。t1线程从休眠中恢复过来再次打印a的值已经变成了2。
也许有同窗看到这里就有疑问了:“咱们不是说synchronized的意思是得到对象锁吗?那么t1线程执行了同步方法f1(),那就应该得到myThread对象的对象锁啊,怎么在它休眠期间另外一条线程主线程也可以执行myThread对象的f2()方法呢?难道是由于t1线程休眠了以后就释放掉对象锁了吗?”
对于这个问题的解释是这样,t1线程执行run()方法,run()方法调用同步方法f1(),则此时t1线程拥有了myThread这个对象的对象锁,接下来执行Thread.sleep(long miliseconds)这个方法,则线程(即t1)进入休眠状态,可是Thread.sleep(long miliseconds)的执行不会致使线程释放掉对象锁。而main线程之因此可以在t1线程休眠以后继续执行myThread.f2(),是由于f2()并非同步方法。咱们一般说“得到对象锁”,实际上更确切直白的含义是“独占该对象的同步方法和同步代码块”。可是对于非同步方法,对象锁是不起做用的。
咱们能够将例子作以下改动:将f2()修改成同步方法,其余不变。你们有兴趣试一下会发现此时的程序执行结果变成了打印a=1 a=1。由于此时f2()为同步方法,t1线程在休眠期间并无释放对象锁,即此时t1线程“独占myThread对象的f1(),f2()方法”。所以此时主线程不可能执行myThread.f2()。只有当t1线程执行完了f1()方法以后,即两次打印a=1 a=1,释放掉对象锁,此时主线程才能继续执行myThread的同步方法f2()。
不少同窗在理解“同步”这个概念时错误地将其理解成为“并行”,从而获得一些混乱的结论,最后变得愈来愈茫然。而经过上面的例子咱们能够看到,其实线程中“同步”的概念更接近于“串行”。即“同一时刻只能有一条线程拥有一个对象的对象锁,在该线程独占该对象的同步方法和同步代码块时,其余线程不能访问该对象的同步方法和同步代码块”。而synchronized关键字的做用是声明同步方法或者同步代码块,执行到这儿的线程能够告诉其余线程说:“嘿,如今这个对象的同步方法和代码块我占了,大家先等着别抢,我用完了大家才能接着用!”。