java多线程之synchronized和volatile关键字
来源:互联网 发布:阿里云香港机房 编辑:程序博客网 时间:2024/05/18 18:55
synchronized同步方法
脏读
在多个线程对同一个对象中的实例变量进行并发访问的时候,取到的数据可能是被更改过的,称之为“脏读”,这就是非线程安全的。解决的方法为synchronized关键字进行同步,使之操作变成同步而非异步。
public class PublicVar { public String username = "A"; public String password = "AA"; synchronized public void setValue(String username, String password) { try { this.username = username; Thread.sleep(5000); this.password = password; System.out.println("setValue method thread name=" + Thread.currentThread().getName() + " username=" + username + " password=" + password); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized public void getValue() {//不加同步将会造成脏读 System.out.println("getValue method thread name=" + Thread.currentThread().getName() + " username=" + username + " password=" + password); }}
public class ThreadA extends Thread { private PublicVar publicVar; public ThreadA(PublicVar publicVar) { super(); this.publicVar = publicVar; } @Override public void run() { super.run(); publicVar.setValue("B", "BB"); }}
public class Test { public static void main(String[] args) { try { PublicVar publicVarRef = new PublicVar(); ThreadA thread = new ThreadA(publicVarRef); thread.start(); Thread.sleep(200);// 打印结果受此值大小影响 publicVarRef.getValue(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
未加同步锁
加了同步锁
多个对象监视器多个锁
多个线程访问多个对象,JVM会创建多个锁
public class Test { public static void main(String[] args) { TestRunable public1 = new TestRunable(); TestRunable public2 = new TestRunable(); ThreadA athread = new ThreadA(public1); athread.start(); ThreadB bthread = new ThreadA(public2); bthread.start(); }}
上面示例是两个线程访问同一个类的两个不同实例对象,效果是异步的方式运行。即时加了同步锁也是异步执行,因为创建了两个对象,将会产生两把锁。
锁重入
当一个线程得到一个对象锁后,再次请求此对象锁是可以再次得到该对象锁的。就是在自己已经获得该对象锁的前提下,还可以再次获取自己的锁。可重入锁也支持在父子类继承的环境中。
public class MyThread extends Thread { @Override public void run() { Service service = new Service(); service.service1(); }}
public class Service { synchronized public void service1() { System.out.println("service1"); service2(); } synchronized public void service2() { System.out.println("service2"); service3(); } synchronized public void service3() { System.out.println("service3"); }}
public class Run { public static void main(String[] args) { MyThread t = new MyThread(); t.start(); }}
synchronized同步语句块
同步语句块的好处
public class Task { private String getData1; /** * synchronized public void doLongTimeTask(){} * 如果同步锁在方法上 * A线程执行的时候会锁住3秒钟,然B线程再执行,效率太低 * 所以同步代码块是效率最高的方法 */ public void doLongTimeTask() { try { System.out.println("begin task"); Thread.sleep(3000); synchronized (this) { getData1 = Thread.currentThread().getName(); } System.out.println(getData1); System.out.println("end task"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
public class MyThread1 extends Thread { private Task task; public MyThread1(Task task) { super(); this.task = task; } @Override public void run() { super.run(); task.doLongTimeTask(); }}
public class MyThread2 extends Thread { private Task task; public MyThread2(Task task) { super(); this.task = task; } @Override public void run() { super.run(); task.doLongTimeTask(); }}
public class Run { public static void main(String[] args) { Task task = new Task(); MyThread1 thread1 = new MyThread1(task); thread1.start(); MyThread2 thread2 = new MyThread2(task); thread2.start(); }}
如果同步方法的话,程序跑完大概在6秒钟左右,A线程B线程各用时3秒钟
如果同步语句块的话,让耗时的操作异步执行,那么程序跑完大概也就3秒钟,效率提升很高。
一半同步一半异步
把上面的Task类修改如
在synchronized 中就是同步,不在synchronized 中就是异步,可以运行看下结果
public class Task { public void doLongTimeTask() { for (int i = 0; i < 100; i++) { System.out.println("nosynchronized threadName=" + Thread.currentThread().getName() + " i=" + (i + 1)); } System.out.println(""); synchronized (this) { for (int i = 0; i < 100; i++) { System.out.println("synchronized threadName=" + Thread.currentThread().getName() + " i=" + (i + 1)); } } }}
死锁
不同的线程都在等待不可能释放的锁,从而导致所有任务都无法完成,造成线程的假死。
public class DealThread implements Runnable { public String username; public Object lock1 = new Object(); public Object lock2 = new Object(); public void setFlag(String username) { this.username = username; } @Override public void run() { if (username.equals("a")) { synchronized (lock1) { try { System.out.println("username = " + username); Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized (lock2) { System.out.println("按lock1->lock2代码顺序执行了"); } } } if (username.equals("b")) { synchronized (lock2) { try { System.out.println("username = " + username); Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized (lock1) { System.out.println("按lock2->lock1代码顺序执行了"); } } } }}
public class Run { public static void main(String[] args) { try { DealThread t1 = new DealThread(); t1.setFlag("a"); Thread thread1 = new Thread(t1); thread1.start(); Thread.sleep(100); t1.setFlag("b"); Thread thread2 = new Thread(t1); thread2.start(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
互相等待,导致线程假死
volatile关键字
volatile关键字提示线程每次从共享内存中读取变量,而不是私有内存。
适用场合是在多个线程中可以感知实例变量被更改了。
在JVM被设置成-server服务器模式运行时,为了线程运行的效率,线程一直在私有堆栈中。其他线程更改的实例变量值却会更新在公共堆栈中。
解决异步死循环
public class RunThread extends Thread { //volatile 关键字 isRunning变量将从公共堆栈中取值 volatile private boolean isRunning = true; public boolean isRunning() { return isRunning; } public void setRunning(boolean isRunning) { this.isRunning = isRunning; } @Override public void run() { System.out.println("进入run了"); while (isRunning == true) { } System.out.println("线程被停止了!"); }}
public class Run { public static void main(String[] args) { try { RunThread thread = new RunThread(); thread.start(); Thread.sleep(1000); thread.setRunning(false); System.out.println("已经赋值为false"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
在-server服务器模式中运行
volatile的非原子性(synchronized的代码块有volatile同步的功能)
volatile关键字增加了多线程之间实例变量的可见性,但是不能保证同步性
public class Service { private boolean isContinueRun = true; public void runMethod() { String anyString = new String(); while (isContinueRun == true) { //synchronized 可以使多个线程访问统一资源具有同步性 //可以同步 工作内存中的私有变量和公共内存中的变量 synchronized (anyString) { } } System.out.println("停下来了!"); } public void stopMethod() { isContinueRun = false; }}
public class ThreadA extends Thread { private Service service; public ThreadA(Service service) { super(); this.service = service; } @Override public void run() { service.runMethod(); }}
public class ThreadB extends Thread { private Service service; public ThreadB(Service service) { super(); this.service = service; } @Override public void run() { service.stopMethod(); }}
public class Run { public static void main(String[] args) { try { Service service = new Service(); ThreadA a = new ThreadA(service); a.start(); Thread.sleep(1000); ThreadB b = new ThreadB(service); b.start(); System.out.println("已经发起停止的命令了!"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
在-server服务器模式中运行
注意事项
**synchronized关键字锁住变量的时候最好不要用String类型的,要考虑字符串常量池的问题
例如:
String str="aaa";String str1="aaa";//java中的字符串常量池会导致同步失效//System.out.print(str==str1);//true//所以最好用 Object o=new Object();synchronized(str){ //TODO}
synchronized关键字加到static静态方法上是给Class类加锁
Class锁可以对类的所有对象实例起作用。
synchronized关键字加到非static静态方法上是给对象加锁
此为读书笔记,还望各位多多指导
0 0
- java多线程之synchronized和volatile关键字
- Java 多线程编程之synchronized 和 volatile关键字
- Java多线程之synchronized和volatile
- java关键字volatile和synchronized在多线程中的应用
- java多线程编程关键字volatile,ThreadLocal和synchronized
- java 关键字synchronized和volatile
- 多线程之synchronized和volatile
- 多线程之 synchronized 和 volatile
- JAVA多线程系列--关键字(volatile,synchronized)
- Java多线程volatile和synchronized
- 学习java基础关键字之synchronized和volatile
- Java 多线程之 synchronized 和 volatile 的比较
- Java多线程之synchronized和volatile的比较
- Java 多线程之 synchronized 和 volatile 的比较
- Java多线程之synchronized关键字
- JAVA多线程之Synchronized关键字
- JAVA 多线程之~~volatile关键字
- java多线程之volatile关键字
- 【前端攻城狮之路】video与audio
- Android的缓存机制(java序列化)
- 日志2016.11.4
- 【Linux4.1.12源码分析】协议栈gro收包之TCP处理
- 【搬自TC_SRM583 Hard】【JZOJ4844】抗拒黄泉 题解
- java多线程之synchronized和volatile关键字
- Android用RxJava combineLatest操作符处理复杂表单验证问题
- hdoj 4198 Quick out of the Harbour(bfs,优先队列)
- 修饰函数的const和函数返回值的const区别
- 无人机——磁力计/电子罗盘 学习及校准
- 随机森林算法原理及OpenCV应用
- 安徽科技学院2016-2017-1学期2013信息与计算科学12班<算法分析与设计>期末测试_题解
- Java课程复习1:
- Ubuntu 15.04 CUDA 7.5 Matlab R2016b Caffe配置