java线程同步等基础知识
2016-05-09 20:05
477 查看
一、线程同步
线程安全API与非线程安全API
StringBuffer是同步的 synchronized append()
StringBuilder不是同步的 append();
Vector 和 Hashtable是同步的
ArrayList和HashMap不是同步的
二、synchronized关键字
多个线程并发读写同一个临界资源是会发生“线程并发”安全等问题
锁机制:
java提供了一种内置的锁机制用来支持原子性:
同步代码快,同步代码快包含两部分:
一个作为锁的对象的引用
一个作为有这个锁保护的代码
synchronized(同步监视器-锁对象引用){
}
-- 若方法 所有代码都需要同步与也可以方法直接加锁
-- 每个java对象都可以用做一个实现同步的锁。线程进入同步代码块之前自动获得锁,并且退出同步代码块时自动释放放锁,而且不论是通过正常途径退出,还是通过抛出异常退出都一样,获得内置锁的唯一正常途径就是进入这个锁保护的同步的代码块和方法/
常见的临界资源(所谓的临界资源可以参考:计算机操作系统临界资源):
--多线程共享实例变量
--多线程共享静态公共变量
解决线程的安全的解决方案:
--异步操作:多线程并发,相当于各干各的
--同步操作:
有先后顺序的操作,相当于你干完我干
测试代码:
/**
* 多线程并发安全问题
* 当多个线程同时操作同一资源是,由于线程切换时机不明确,导致出现逻辑混乱
* 严重时可能导致系统崩溃
*
* @author soft01
*
*/
测试代码:
/**
* 有效的缩小同步范围可以保证在安全
* 的前提下提高并发的效率
* 在这个程序中我们提前假设 :换衣服时--->
可能导致 取错别人的衣服,所以在需要排队.
* @author soft01
*
*/
测试代码:
/**
* synchronized也称为“互斥锁”;
* 当synchronized修饰的两端代码,但是“锁对象”相同时,即是互斥锁
* @author soft01
*
*/
测试结果:
Thread[Thread-0,5,main]正在调用方法
Thread[Thread-0,5,main]调用完毕
Thread[Thread-1,5,main]正在调用方法
Thread[Thread-1,5,main]调用完毕
三 集合线程安全
/**
* ArrayList,Linkedlist,HashSet 都不是线程安全的,
*Map常用的实现类HshMap也不是线程安全的
* 而线程安全的集合List是Vector,线程安全的Map的实现类是HashTable
* 可以使用Collections提供的静态方法可以将当前的集合或Map转换为线程安全
* Collection 是接口
* Collections是工具类
*
* @author soft01
*
*/
测试代码:
线程安全API与非线程安全API
StringBuffer是同步的 synchronized append()
StringBuilder不是同步的 append();
Vector 和 Hashtable是同步的
ArrayList和HashMap不是同步的
二、synchronized关键字
多个线程并发读写同一个临界资源是会发生“线程并发”安全等问题
锁机制:
java提供了一种内置的锁机制用来支持原子性:
同步代码快,同步代码快包含两部分:
一个作为锁的对象的引用
一个作为有这个锁保护的代码
synchronized(同步监视器-锁对象引用){
}
-- 若方法 所有代码都需要同步与也可以方法直接加锁
-- 每个java对象都可以用做一个实现同步的锁。线程进入同步代码块之前自动获得锁,并且退出同步代码块时自动释放放锁,而且不论是通过正常途径退出,还是通过抛出异常退出都一样,获得内置锁的唯一正常途径就是进入这个锁保护的同步的代码块和方法/
常见的临界资源(所谓的临界资源可以参考:计算机操作系统临界资源):
--多线程共享实例变量
--多线程共享静态公共变量
解决线程的安全的解决方案:
--异步操作:多线程并发,相当于各干各的
--同步操作:
有先后顺序的操作,相当于你干完我干
测试代码:
/**
* 多线程并发安全问题
* 当多个线程同时操作同一资源是,由于线程切换时机不明确,导致出现逻辑混乱
* 严重时可能导致系统崩溃
*
* @author soft01
*
*/
public class SyncDemo1 { public static void main(String[] args) { /* * 当一个方法中的局部内部类引用该方法的其他局部变量时,这个变量必须被申明为final的 * Thread t1=new Thread()作为内部类 * */ final Table table=new Table(); Thread t1=new Thread(){ public void run(){ while(true){ int bean=table.getBean(); Thread.yield(); System.out.println(getName()+":"+bean); } } }; t1.start(); Thread t2=new Thread(){ public void run(){ while(true){ int bean=table.getBean(); Thread.yield(); System.out.println(getName()+":"+bean); } } }; t2.start(); } } class Table{ private int beans=20; /* * 当一个方法被SYSNCHRONIZED修饰后, * 该方法成为“同步方法”多个线程不能同时进入到内部 */ public synchronized int getBean(){ if(beans==0){ throw new RuntimeException("没有豆子"); } Thread.yield();//模拟进程切换 return beans--; } }
测试代码:
/**
* 有效的缩小同步范围可以保证在安全
* 的前提下提高并发的效率
* 在这个程序中我们提前假设 :换衣服时--->
可能导致 取错别人的衣服,所以在需要排队.
* @author soft01
*
*/
public class SyncDemo2 { public static void main(String[] args) { final Shop shop=new Shop(); Thread t0=new Thread(){ public void run() { shop.bye(); } }; Thread t1=new Thread(){ public void run() { shop.bye(); } }; t0.start(); t1.start(); } } class Shop{ public void bye(){ try{ Thread t=Thread.currentThread(); System.out.println(t+"正在挑衣服"); Thread.sleep(5000); /* * 同步块可以缩小同步范围 * 但是必须保证和"同步监视器":即 上锁对象 * 是同一个才可以 * 通常,在一个方法中使用this来表示 */ synchronized (this) {//这里的this不能换成:new object(),必须要保证看到的是同一对象 System.out.println(t+"正在试衣服"); Thread.sleep(5000); } System.out.println("结帐离开"); }catch(Exception e){ e.printStackTrace(); } } }
测试代码:
/**
* synchronized也称为“互斥锁”;
* 当synchronized修饰的两端代码,但是“锁对象”相同时,即是互斥锁
* @author soft01
*
*/
public class Synchronized { public static void main(String[] args) { final Boo boo=new Boo(); Thread t1=new Thread(){ public void run(){ boo.methodA(); } }; Thread t2=new Thread(){ public void run(){ boo.methodB(); } }; t1.start(); t2.start(); } } class Boo{ public synchronized void methodA(){ Thread t=Thread.currentThread(); System.out.println(t+"正在调用方法"); try{ Thread.sleep(5000); }catch (InterruptedException e) { e.printStackTrace(); // TODO: handle exception } System.out.println(t+"调用完毕"); } public synchronized void methodB(){ Thread t=Thread.currentThread(); System.out.println(t+"正在调用方法"); try{ Thread.sleep(5000); }catch (InterruptedException e) { e.printStackTrace(); // TODO: handle exception } System.out.println(t+"调用完毕"); } }
测试结果:
Thread[Thread-0,5,main]正在调用方法
Thread[Thread-0,5,main]调用完毕
Thread[Thread-1,5,main]正在调用方法
Thread[Thread-1,5,main]调用完毕
三 集合线程安全
/**
* ArrayList,Linkedlist,HashSet 都不是线程安全的,
*Map常用的实现类HshMap也不是线程安全的
* 而线程安全的集合List是Vector,线程安全的Map的实现类是HashTable
* 可以使用Collections提供的静态方法可以将当前的集合或Map转换为线程安全
* Collection 是接口
* Collections是工具类
*
* @author soft01
*
*/
测试代码:
import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; public class SyncApiDemo { public static void main(String[] args) { List<String> list=new ArrayList<String>(); list.add("one"); list.add("two"); list.add("three"); list.add("four"); /* * 将给定的List集合转换为线程安全的集合 * 返回的集合中仍然包含所有元素 */ list=Collections.synchronizedList(list); System.out.println(list); //HashSet不是线程安全的 Set<String> set=new HashSet<String>(list); //转换为线程安全集合 set=Collections.synchronizedSet(set); Map<String,Integer> map=new HashMap<String, Integer>(); map.put("语文",1); map.put("数学",3); map.put("英语",2); map=Collections.synchronizedMap(map); System.out.println(map); } }
相关文章推荐
- Java 设计模式(十二) 依赖倒置原则(DIP)
- Java核心技术(五) —— 泛型程序设计(1)
- Maven学习3之eclipse安装maven
- 用Java代码打印菱形
- Ubuntu搭建Java开发环境
- 安卓java层操作数据库
- java类型
- java 类文件结构
- Java中的输出流
- java四舍五入保留几位小数
- Java Web实用小知识02
- java基础之内部类总结利用招聘
- JAVA基础之——HashSet中是如何判断元素是否重复的
- 将Eclipse项目导入Android Studio出现中文乱码的问题
- JDk安装及配置
- javaweb常见易错问题大汇总
- Spring声明式事务配置管理方法
- Java之Callable Future FutureTask Exectuor使用笔记
- JAVA基础之——深入理解Java的接口和抽象类
- 完整全面的Java资源库(包括构建、操作、代码分析、编译)