锁定老帖子 主题:java 基础,关于线程安全
精华帖 (0) :: 良好帖 (3) :: 新手帖 (0) :: 隐藏帖 (3)
|
|
---|---|
作者 | 正文 |
发表时间:2010-06-04
最后修改:2010-06-04
线程安全的本质体现在两个方面, A变量安全:多线程同时运行一段代码 B线程同步:一个线程还没执行完,另一个线程又进来接着执行。 看个简单的例子。 public class ThreadSafe implements java.lang.Runnable { int num = 1; public void run() { for (int i = 0; i < 3; i++) { num = num + 1; try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + num); } } } TestMan.java 写道
package com.java.thread.test;
public class TestMan { public static void main(String[] args) { Runnable safe=new ThreadSafe(); Thread thread1=new Thread(safe,"thread1"); Thread thread2=new Thread(safe,"thread2"); thread1.start(); thread2.start(); } } 运行结果 num is value +===thread2---------3 很明显是错误的,应为两个线程共享同一个变量。这里就是变量的安全问题。 解决办法: 1抛弃单实例,多线程的方式,用多实例,多线程的方式,这样就和单线程是一个样了,不会出错,但是是最接近传统的编程模式 2不要用类的实例变量,经可能把变量封装到方法内部。 1类的解决办法的代码。 public class TestMan { public static void main(String[] args) { Runnable safe=new ThreadSafe(); Runnable safe2=new ThreadSafe(); Thread thread1=new Thread(safe,"thread1"); Thread thread2=new Thread(safe2,"thread2"); thread1.start(); thread2.start(); } } 运行结果 num is value +===thread1---------2 public class ThreadSafe implements java.lang.Runnable { public void run() { int num = 1; for (int i = 0; i < 3; i++) { num = num + 1; try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + num); } } } public class TestMan { public static void main(String[] args) { Runnable safe=new ThreadSafe(); Thread thread1=new Thread(safe,"thread1"); Thread thread2=new Thread(safe,"thread2"); thread1.start(); thread2.start(); } } 运行结果 num is value +===thread2---------2
这两种办法,比较推荐适用第二个办法,就是把变量经可能的封装到风发内部,这样他们就是线程的私有变量了。另外,从jdk1.2后,推出了threadlocal 对象,它作为线程的一个局部变量,可以为每个线程创建一个副本,用来保存每个线程的属性,各是各的,互不干扰。单每个threadlocal变量只能保存一个变量,假如有多个变量要保存,那么就要写多个threadlocal对象。
我们把代码改写一下。 public class ThreadSafe implements java.lang.Runnable { ThreadLocal<Integer> local=new ThreadLocal<Integer>(); public void run() { for (int i = 0; i < 3; i++) { if(local.get()==null){ local.set(new Integer(1)); } int num=local.get().intValue(); num=num+1; local.set(new Integer(num)); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + local.get().intValue()); } } } public class TestMan { public static void main(String[] args) { Runnable safe=new ThreadSafe(); Thread thread1=new Thread(safe,"thread1"); Thread thread2=new Thread(safe,"thread2"); thread1.start(); thread2.start(); } } 运行结果 num is value +===thread2---------2 结果是一样的,所以这里变量安全有3个办法可以解决。
然后在说说线程的同步的问题。我们看上面的运行结果。 num is value +===thread2---------2 就 可以看出他们不是线程同步的,是thread1和thread2在交替执行的。在有些情况下,要求一段代码在运行的过程中是一个不可分割的实体,就是原子的。就是说当已经有线程在执行这段代码的时候,其他的线程必须等待他执行完毕后才能竟来执行,这就是所谓的线程同步。
java通过同步锁来执行线程的同步和等待,也就是说,要不间断执行的代码需要放在synchronized关键字标识的代码块中。可以用来修饰代码块,也可以修饰方法。
public class ThreadSafe implements java.lang.Runnable{ public synchronized void run() { int num = 1; for (int i = 0; i < 3; i++) { num = num + 1; try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + num); } } } public class TestMan { public static void main(String[] args) { Runnable safe=new ThreadSafe(); Thread thread1=new Thread(safe,"thread1"); Thread thread2=new Thread(safe,"thread2"); thread1.start(); thread2.start(); } } 运行结果 um is value +===thread1---------2
可以看到thread1运行结束后thread2才开始运行的。代码还可以这么写 public class ThreadSafe implements java.lang.Runnable { public void run() { int num = 1; synchronized (this) { for (int i = 0; i < 3; i++) { num = num + 1; try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("num is value +===" + Thread.currentThread().getName() + "---------" + num); } } } } 在启用同步锁机制以后,需要避免 1无线等待,,线程B等待线程A执行完毕,然后线程A确进入了死循环。 2循环等待:两个线程相互调用,都要求要同步执行,这个时候就先会循环等待,我等你执行,你也在等我执行,这个时候就死锁了。
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-06-05
很好,threadlocal, Thread thread1=new Thread(safe,"thread1"); ,Runnable safe=new ThreadSafe();
哪个用得多一些, |
|
返回顶楼 | |
发表时间:2010-06-06
最后修改:2010-06-06
变量安全别把volatile忘记了……,在你需要停止线程的时候,这个很有用.
|
|
返回顶楼 | |
发表时间:2010-06-06
很好~虽然很基础,但是解决了我一个长期困扰我的问题~
|
|
返回顶楼 | |
发表时间:2010-06-06
不错,最近才开始学线程,收获不少啊!
|
|
返回顶楼 | |
发表时间:2010-06-06
多实例 多线程?
这个“多线程”就是多个Thread对象 但对所谓的 "多实例" 一直不是很了解 |
|
返回顶楼 | |
发表时间:2010-06-06
还要一个问题
synchronized (this) { for (int i = 0; i < 3; i++) { num = num + 1; try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("num is value +===" + Thread.currentThread().getName() + "---------" + num); } } 这里的this 到底指什么???? |
|
返回顶楼 | |
发表时间:2010-06-07
最后修改:2010-06-07
明天的昨天 写道 还要一个问题
synchronized (this) { for (int i = 0; i < 3; i++) { num = num + 1; try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("num is value +===" + Thread.currentThread().getName() + "---------" + num); } } 这里的this 到底指什么???? 锁定该类对象的方法块,同时指让一个线程访问 |
|
返回顶楼 | |
发表时间:2010-06-07
是很基础,不过我学到了东西
|
|
返回顶楼 | |
发表时间:2010-06-09
|
|
返回顶楼 | |
浏览 5954 次