大漠驼铃

置身浩瀚的沙漠,方向最为重要,希望此blog能向大漠驼铃一样,给我方向和指引。
Java,Php,Shell,Python,服务器运维,大数据,SEO, 网站开发、运维,云服务技术支持,IM服务供应商, FreeSwitch搭建,技术支持等. 技术讨论QQ群:428622099
随笔 - 238, 文章 - 3, 评论 - 117, 引用 - 0
数据加载中……

Java线程学习(2):关键字synchronized

有了synchronized关键字,多线程程序的运行结果将变得可以控制。synchronized关键字用于保护共享数据。请大家注意"共享数据", 你一定要分清哪些数据是共享数据,JAVA是面向对象的程序设计语言,所以初学者在编写多线程程序时,容易分不清哪些数据是共享数据。请看下面的例子:

实例一:
public class FirstThread implements Runnable{
public synchronized void run(){
for(int i=1;i<10;i++){
System.out.println(
""+i);
}
}
public FirstThread(){
}
public static void main(String[] args){
Runnable r1
=new FirstThread();
Runnable r2
=new FirstThread();
Thread t1
=new Thread(r1);
Thread t2
=new Thread(r2);
t1.start();
t2.start();

}

}
在这个程序中,run()被加上了synchronized关键字。在main方法中创建了两个线程。你可能会认为此程序的运行结果一定为:0123456789  0123456789。答案不是这样子的,这个程序中synchronized关键字保护的不是共享数据(其实在这个程序中synchronized关 键字没有起到任何作用,此程序的运行结果是不可预先确定的)。这个程序中的t1,t2是两个对象(r1,r2)的线程。JAVA是面向对象的程序设计语 言,不同的对象的数据是不同的,r1,r2有各自的run()方法,而synchronized使同一个对象的多个线程,在某个时刻只有其中的一个线程可 以访问这个对象的synchronized数据。每个对象都有一个"锁标志",当这个对象的一个线程访问这个对象的某个synchronized数据时, 这个对象的所有被synchronized修饰的数据将被上锁(因为"锁标志"被当前线程拿走了),只有当前线程访问完它要访问的 synchronized数据时,当前线程才会释放"锁标志",这样同一个对象的其它线程才有机会访问synchronized数据。
实例二:
public class SecondThread implements Runnable{
public synchronized void run(){
for(int i=1;i<10;i++){
System.out.println(
""+i);
}
}
public SecondThread(){
}
public static void main(String[] args){
Runnable r
=new SecondThread();
//Runnable r2
=new FirstThread();
Thread t1
=new Thread(r);
Thread t2
=new Thread(r);
t1.start();
t2.start();

}

}

如果你运行1000次这个程序,它的输出结果也一定每次都是:01234567890123456789。因为这里的synchronized保护的是共享数据。t1,t2是同一个对象(r)的两个线程,当其中的一个线程(例如:t1)开始执行run()方法时,由于run()受 synchronized保护,所以同一个对象的其他线程(t2)无法访问synchronized方法(run方法)。只有当t1执行完后t2才有机会 执行。

实例三:

public class ThreeThread implements Runnable{
public  void run(){
synchronized(this){
for(int i=1;i<10;i++){
System.out.println(
""+i);
}}
}
public ThreeThread(){
}
public static void main(String[] args){
Runnable r
=new SecondThree();
//Runnable r2=new FirstThread();
Thread t1=new Thread(r);
Thread t2
=new Thread(r);
t1.start();
t2.start();

}

}

这个程序与示例2的运行结果一样。在可能的情况下,应该把保护范围缩到最小,可以用示例3的形式,this代表"这个对象"。没有必要把整个run()保护起来,run()中的代码只有一个for循环,所以只要保护for循环就可以了。

实例四:
public class FourThread implements Runnable{
public  void run(){
for(int i=1;i<10;i++){
System.out.println(
Thread.currentThread().getName()+"forloop"+i);
}

synchronized(this){
for(int i=1;i<10;i++){
System.out.println(
Thread.currentThread().getName()+"synchronized"+i);
}}
}
public SecondThread(){
}
public static void main(String[] args){
Runnable r
=new ThreeThread();
//Runnable r2=new FirstThread();
Thread t1=new Thread(r);
Thread t2
=new Thread(r);
t1.start();
t2.start();

}

}
t1_name:forloop:0
t1_name:forloop:1
t1_name:forloop:2
t2_name:forloop:0
t1_name:forloop:3
t2_name:forloop:1
t1_name:forloop:4
t2_name:forloop:2
t1_name:synchronizedforloop:0
t2_name:forloop:3
t1_name:synchronizedforloop:1
t2_name:forloop:4
t1_name:synchronizedforloop:2
t1_name:synchronizedforloop:3
t1_name:synchronizedforloop:4
t2_name:synchronizedforloop:0
t2_name:synchronizedforloop:1
t2_name:synchronizedforloop:2
t2_name:synchronizedforloop:3
t2_name:synchronizedforloop:4
第一个for循环没有受synchronized保护。对于第一个for循环,t1,t2可以同时访问。运行结果
表明t1执行到了k=2 时,t2开始执行了。t1首先执行完了第一个for循环,此时还没有执行完第一个
for循环(t2刚执行到k=2)。t1开始执行第二个for循环,当 t1的第二个for循环执行到k=1时,t2
的第一个for循环执行完了。http://bianceng.cn(编程入门)
t2想开始执行第二个for循环,但由于t1首先执行了第二个for循环,这个对象的锁标志自然在
t1手中(synchronized方法的执行权也就落到了t1手中),在t1没执行完第二个for循环的时候,它
是不会释放锁标志的。
所以t2必须等到t1执行完第二个for循环后,它才可以执行第二个for循环

posted on 2009-02-26 19:43 草原上的骆驼 阅读(338) 评论(0)  编辑  收藏 所属分类: JAVA基础知识


只有注册用户登录后才能发表评论。


网站导航: