`

[转]java线程安全总结

阅读更多
http://www.iteye.com/wiki/jvm/2877-synchronized-volatile

一.java的内存模型JMM(解决可见性和有序性) 规定了jvm主内存
多线程不能相互传递数据,用共享变量

每个线程都有工作内存,其存储了主内存某些对象的副本.:
1)从主存复制对象到当前工作内存(read and load)
2)改变共享内存(use and assign) (其他线程可见)
3)工作内存数据刷新主存相关内容(store and write)

多次赋值时,可能只对工作内存副本操作,最后一次才同步到主存
导致不同步会出问题.
synchronized关键字保证了多个线程对于同步块是互斥的
而volatile关键字之解决多线程的内存可见性问题
二.java的线程同步机制

//不同步
package com.test;

public class Account {

	private int balance;

	public Account(int balance) {
		this.balance = balance;
	}

	public int getBalance() {
		return balance;
	}

	public void add(int num) {
		balance = balance + num;
	}

	public void withdraw(int num) {
		balance = balance - num;
	}

	public static void main(String[] args) throws InterruptedException {
		for (int i = 0; i < 100; i++) {
			Account account = new Account(1000);
			Thread a = new Thread(new AddThread(account, 20), "add");//创建thread
			Thread b = new Thread(new WithdrawThread(account, 20), "withdraw");
			a.start();//启动
			b.start();
			a.join();
			b.join();
			System.out.println(i+":"+account.getBalance());
		}
	}

	static class AddThread implements Runnable {
		Account account;
		int amount;

		public AddThread(Account account, int amount) {
			this.account = account;
			this.amount = amount;
		}

		public void run() {
			for (int i = 0; i < 1000000; i++) {
				account.add(amount);
			}
		}
	}

	static class WithdrawThread implements Runnable {
		Account account;
		int amount;

		public WithdrawThread(Account account, int amount) {
			this.account = account;
			this.amount = amount;
		}

		public void run() {
			for (int i = 0; i < 1000000; i++) {
				account.withdraw(amount);
			}
		}
	}
}


public synchronized void add(int num) //锁方法所在对象
public  static synchronized void add(int num) //锁方法所在的class

//在并发环境下,一个没有共享的对象作为锁是没有意义的
Object lock=new Object(); 
     synchronized (lock){ 
        //do something 
     }

锁有两个队列 :就绪(将获得锁),阻塞(被阻塞的进程)

wait(放弃锁)-->阻塞-->notify-->就绪-->cpu调度
临界区代码:
1)获得同步锁
2)清空工作内存
3)主存copy变量到工作内存
4)处理
5)工作内存-->主存
6)释放锁

//线程安全

public class Account {
	List<Object> eggs = new ArrayList<Object>();

	public synchronized Object getEgg() {
		if (eggs.size() == 0) {
			try {
				wait(); // 放弃锁
			} catch (InterruptedException e) {
			}
		}

		Object egg = eggs.get(0);//
		System.out.println("Get Egg,Eggs' size:" + eggs.size());
		System.out.println("============================");
		eggs.clear();// 清空盘子
		notify(); // 唤醒
		return egg;
	}

	public synchronized void putEgg(Object egg) {
		if (eggs.size() > 0) {
			try {
				wait();
			} catch (InterruptedException e) {
			}
		}
		eggs.add(egg);// 往盘子里放鸡蛋
		System.out.println("Put Egg,Eggs' Size:" + eggs.size());
		notify();// 唤醒阻塞队列的某线程到就绪队列
	}

	public static void main(String[] args) throws InterruptedException {
		Account account = new Account();
		Thread put = new Thread(new Put(account));
		Thread get = new Thread(new Get(account));
		put.start();
		get.start();
		// put.join();
		// get.join();

	}

	static class Put implements Runnable {
		Account account;

		Put(Account a) {
			this.account = a;
		}

		public void run() {
			for (int i = 0; i < 100000; i++) {
				Object egg = new Object();
				account.putEgg(egg);
			}
		}

	}

	static class Get implements Runnable {
		Account account;

		Get(Account a) {
			this.account = a;
		}

		public void run() {
			for (int i = 0; i < 1000000; i++) {
				account.getEgg();
			}
		}

	}
}


1 开始,A调用plate.putEgg方法,此时eggs.size()为0,因此顺利将鸡蛋放到盘子,还执行了notify()方法,唤醒锁的阻塞队列的线程,此时阻塞队列还没有线程。
2 又有一个A线程对象调用plate.putEgg方法,此时eggs.size()不为0,调用wait()方法,自己进入了锁对象的阻塞队列。
3 此时,来了一个B线程对象,调用plate.getEgg方法,eggs.size()不为0,顺利的拿到了一个鸡蛋,还执行了notify()方法,唤醒锁的阻塞队列的线程,此时阻塞队列有一个A线程对象,唤醒后,它进入到就绪队列,就绪队列也就它一个,因此马上得到锁,开始往盘子里放鸡蛋,此时盘子是空的,因此放鸡蛋成功。
4 假设接着来了线程A,就重复2;假设来料线程B,就重复3。


任何被volatile修饰的变量,都不拷贝副本到工作内存,任何修改都及时写在主存
只保证可见性,不保证有序性
public class VolatileTest{ 
  public volatile int a; 
  public void add(int count){ 
       a=a+count; 
  } 


//适合场景
满足条件
1)对变量的写操作不依赖于当前值。
2)该变量没有包含在具有其他变量的不变式中
用volatile声明了,读取主存副本到工作内存和同步a到主存的步骤,相当于是一个原子操作
public void setA(int a){ 
      this.a=a; 
  } 
分享到:
评论

相关推荐

    java线程安全总结.doc

    以下是对Java线程安全的深入总结: ### 一、线程安全的定义 线程安全是指当多个线程访问同一块代码时,如果每个线程都能得到预期的结果,且不产生数据不一致或同步问题,那么这块代码就被称为线程安全的。Java中的...

    java线程安全总结

    java线程安全总结 帮助你们更好的理解什么是线程 什么是网络安全

    java线程安全总结.pdf

    标题“java线程安全总结.pdf”指向了文档的主要内容:这是关于Java编程语言中的线程安全问题的总结性资料。线程安全是并发编程中的一个核心概念,它与Java多线程技术紧密相关。文档的描述信息非常简洁,只是重复了...

    java多线程编程总结

    #### 一、Java线程:概念与原理 - **操作系统中线程和进程的概念** 当前的操作系统通常都是多任务操作系统,多线程是一种实现多任务的方式之一。在操作系统层面,进程指的是内存中运行的应用程序,每个进程拥有...

    java线程安全总结.doc下载

    Java线程安全是多线程编程中的一个核心概念,尤其在服务器端开发中,理解并掌握线程安全至关重要。线程安全是指当多个线程访问一个对象时,如果这个对象的状态始终保持一致,那么我们就说这个对象是线程安全的。在...

    Java多线程编程总结

    - `java.util.concurrent.atomic` 包提供了原子类,用于在不需要锁的情况下进行线程安全的操作。 #### 二十、Java线程:新特征-障碍器 - `CyclicBarrier` 和 `Phaser` 类允许一组线程相互等待,直到所有线程到达一...

    java线程安全性总结

    用思维导图将Java线程安全性相关基本概念联系起来

    java线程安全总结[汇编].pdf

    Java线程安全是多线程编程中的一个核心概念,...总结起来,Java线程安全是一个复杂而又重要的主题,涉及到多线程编程中的各种机制和策略。理解并掌握这些知识点,可以帮助开发者编写出高效、稳定、线程安全的Java程序。

    Java线程安全问题_动力节点Java学院整理

    其实java的多线程并发问题最终都会反映在java的内存模型上,所谓线程安全无非是要控制多个线程对某个资源的有序访问或修改。总结java的内存模型,要解决两个主要的问题:可见性和有序性。我们都知道计算机有高速缓存...

    Java多线程知识点总结

    Java提供了多种机制来保证线程安全,比如使用synchronized关键字来同步方法或代码块,实现线程之间的同步。当一个线程试图进入一个已经被另一个线程持有的同步代码块时,它将进入阻塞状态,直到同步代码块的执行线程...

    Java多线程的总结

    Java集合框架中有一些线程安全的类,如Vector、HashTable、ConcurrentHashMap等,它们内部实现了同步机制,可以在多线程环境中直接使用,避免了手动同步的复杂性。 十、线程局部变量 ThreadLocal为每个线程都创建了...

    Java线程知识总结

    Java线程知识是Java开发中不可或缺的部分,尤其在构建高性能、高并发的应用程序时显得尤为重要。线程允许程序在同一时间处理多个任务,提高了CPU的利用率和程序的响应速度。 在Java中,线程是由Java虚拟机(JVM)...

    JAVA多线程总结

    **一、Java线程:概念与原理** 1. **线程与进程**: - **进程**:是操作系统资源分配的基本单位,每个进程都有独立的内存空间。 - **线程**:是进程中的一个执行流,线程间共享进程的内存空间。在Java中,每个...

    Java线程详细总结

    ### Java线程详细总结 #### 一、Java线程简介 Java中的线程是一个轻量级的进程,它能够在一个程序中并发地执行多个任务。Java语言直接支持线程的概念,这使得Java成为多线程编程的理想选择。与进程相比,线程具有...

    Java 多线程 订票 示例 线程安全

    总结起来,Java多线程在实现订票系统时,需要注意线程安全问题,通过合理使用同步机制、Lock接口和原子类,可以在保证数据一致性的同时提高并发性能。在实际开发中,要根据业务场景选择合适的线程安全策略,以达到...

    java 多线程设计模式 进程详解

    非线程安全的类 总结 第九章 多处理器机器上的并行化 单线程程序并行化 内层循环线程化 循环输出 多处理器扩展 总结 第十章 线程组 线程组概念 创建线程组 线程组方法 操作线程组 线程组、线程和安全 总结

Global site tag (gtag.js) - Google Analytics