java线程安全
来源:互联网 发布:java 中string replace 编辑:程序博客网 时间:2024/06/12 03:30
在网上看了好多文章大家不尽相同,所以,我想自己动手试一下,第一次写文章,大家多指教
第一种:synchronized方法
package com.fn.test.threadsafe;public class Test { public synchronized void iteration(String name){ for (int i = 0; i < 5; i++) { System.out.println(name+":"+i); } } public synchronized void iteration2(String name){ for (int i = 0; i < 5; i++) { System.out.println(name+":"+i); } }}
测试类
public class test_main { public static void main(String[] args) { //线程安全 final Test test=new Test(); Thread test1=new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub test.iteration("test1"); } }); Thread test2=new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub test.iteration2("test2"); } }); test1.start(); test2.start(); }
运行结果
test1:0test1:1test1:2test1:3test1:4test2:0test2:1test2:2test2:3test2:4
上面的这个运行结果证明在一个实例方法上添加关键字synchronized 获得的是对象锁
第二种:synchronized(this)
package com.fn.test.threadsafe;public class Test { public void iteration(String name){ synchronized(this){ for (int i = 0; i < 5; i++) { System.out.println(name+":"+i); } } } public void iteration2(String name){ synchronized(this){ for (int i = 0; i < 5; i++) { System.out.println(name+":"+i); } } }}
运行结果
test1:0test1:1test1:2test1:3test1:4test2:0test2:1test2:2test2:3test2:4
测试类代码同上
从运行结果中可以看到synchronized(this)获得也是对象锁
第三种:synchronized(obj)
package com.fn.test.threadsafe;public class Test { private Integer num=0; private Integer sum=0; public void iteration(String name){ synchronized(num){ for (int i = 0; i < 5; i++) { num++; System.out.println(name+":"+num); } } } public void iteration2(String name){ synchronized(sum){ for (int i = 0; i < 5; i++) { sum--; System.out.println(name+":"+sum); } } }}
运行结果
test2:-1test2:-2test2:-3test2:-4test2:-5test1:1test1:2test1:3test1:4test1:5
这样的运行结果打翻了我之前的了解,我本以为synchronized(num)获得的是num这个对象的锁,但是从运行结果上看,这种方式依然得到的是对象锁。
第四种:volatile
这个关键字是无意中发现的,后来通过百度了解到这个关键字的作用是修饰一个对象,然后告诉java虚拟机,这个对象的值可能会被其它线程改变,所以每次使用该对象的时候就要重新获取,而不是使用寄存器中的值
package com.fn.test.threadsafe;public class Test { private volatile Integer num=0; private Integer sum=0; public void iteration(String name){ for (int i = 0; i < 5; i++) { num++; System.out.println(name+":"+num); } } public void iteration2(String name){ for (int i = 0; i < 5; i++) { num--; System.out.println(name+":"+num); } } public void showNum(){ System.out.println("num="+num); }}
测试类有所改变所以再发一次
package test;import java.awt.Label;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;import java.util.List;import com.fn.test.genericity.Apple;import com.fn.test.genericity.Fruit;import com.fn.test.genericity.FujiApple;import com.fn.test.threadsafe.Test;import com.fn.test.threadsafe.UserAccount;public class test_main { public static void main(String[] args) { //线程安全 final Test test=new Test(); Thread test1=new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub test.iteration("test1"); } }); Thread test2=new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub test.iteration2("test2"); } }); test1.start(); test2.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } test.showNum(); }
运行结果1
test1:0test2:0test1:1test2:0test1:1test2:0test1:1test2:0test1:1test2:0num=0
运行结果2
test1:1test2:1test1:2test2:1test1:2test2:1test1:2test2:1test1:2test2:1num=1
两次的运行结果不一样,想必大家已经知道为什么了,因为在去重新获取的这一段时间,它的值被再次改变了,所以这个关键字并不能保证数据并发线程安全
第五种: Lock
package com.fn.test.threadsafe;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class Test { private Integer num=0; private Integer sum=0; Lock lock = new ReentrantLock(); public void iteration(String name){ try { lock.lock(); for (int i = 0; i < 5; i++) { num++; System.out.println(name+":"+num); } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); }finally{ lock.unlock(); } } public void iteration2(String name){ try { lock.lock(); for (int i = 0; i < 5; i++) { num--; System.out.println(name+":"+num); } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); }finally{ lock.unlock(); } } public void showNum(){ System.out.println("num="+num); }}
运行结果
test1:1test1:2test1:3test1:4test1:5test2:4test2:3test2:2test2:1test2:0num=0
通过运行结果可以看到是可以保证线程安全的,它的原理是每次lock()的时候检查Lock对象是否已经上锁,如果已经上锁,那就等待解锁,负责就执行并上锁
第六种:ThreadLocal
package com.fn.test.threadsafe;public class Test { private ThreadLocal<Integer> num=new ThreadLocal<Integer>(){ protected Integer initialValue() {return 0;}; }; private Integer sum=0; public void iteration(String name){ for (int i = 0; i < 5; i++) { num.set(num.get()+1);; System.out.println(name+":"+num.get()); } } public void iteration2(String name){ for (int i = 0; i < 2; i++) { num.set(num.get()-1);; System.out.println(name+":"+num.get()); } } public void showNum(){ System.out.println("num="+num.get()); }}
运行结果
test2:-1test1:1test2:-2test1:2test1:3test1:4test1:5num=0
结果表明ThreadLocal只是为每个访问该对象的线程提供一个该对象的复制值版,所以当运行完成之后打印num的时候并没有改变num的值(包括主线程),常用于资源类对象,如数据库连接这种不需要同步,只需要解决线程安全问题的地方
- Java线程安全和非线程安全
- Java线程安全和非线程安全
- Java线程安全和非线程安全
- Java线程安全和非线程安全
- Java线程安全和非线程安全
- Java线程安全和非线程安全
- Java线程安全和非线程安全
- Java线程安全和非线程安全
- Java线程安全和非线程安全
- Java线程安全和非线程安全
- Java线程安全和非线程安全
- Java线程安全和非线程安全
- Java线程安全和非线程安全
- Java线程安全和非线程安全
- Java线程安全和非线程安全
- Java线程安全和非线程安全
- Java线程安全和非线程安全
- Java线程安全和非线程安全
- HBase入门篇
- 自己总结的 UtilsMacro.h 工具类头文件
- Alex 的 Hadoop 菜鸟教程: 第7课 Sqoop2 导入教程
- hdu3506 Monkey Party
- CocoaPods pod install/pod update更新慢的问题
- java线程安全
- mongoDB子文档列表更新
- Ubuntu10.04安装Macbuntu主题以后底部panel消失
- 进程控制的相关知识
- 【Howie玩docker】-docker安装
- git 忽略已经提交的文件
- 淄博传统名菜——酥锅的做法
- Beautiful Soup 提取网页
- Android中Service(服务)和Thread(线程)的关系