--------------------------------------------------------------线程安全:
就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。 相反地,
--------------------------------------------------------------线程不安全:
就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得的数据是脏数据。
-------------------------------------------------------------字符串和集合的线程安全
从字符串的拼接和读取来看,StringBuilder的速度比StringBuffer要快。这是因为Stringbuffer中方法大都采用了synchronized的关键字修饰。也就是说,StringBuffer中所有的方法都要加锁,所以好多操作看上去都是线性操作的。所以要慢些。就好像集合HashTable和HashMap一样,HashTable是线程安全的,很多方法都是synchronized方法,而HashMap不是线程安全的,但其在单线程程序中的性能比HashTable要高。StringBuffer和StringBuilder类的区别也是如此,他们的原理和操作基本相同,区别在于StringBuffer支持并发操作,线性安全的,适 合多线程中使用。StringBuilder不支持并发操作,线性不安全的,不适合多线程中使用。新引入的StringBuilder类不是线程安全的,但其在单线程中的性能比StringBuffer高。
package yzp.基础学习.线程相关.线程安全; import java.util.HashMap; import java.util.Hashtable; /** * Created by Administrator on 2018/7/21 0021. * 测试线程安全类 */ public class testThreadSave { public static void main(String[] args) { //---测试StringBuilder和StringBuffer的线程安全性 //testStrBuilderAndStrBuffer(); //---测试HashMap和Hashtable的线程安全性 //testHashMapAndHashtable(); } /** * -------------测试HashMap和Hashtable的线程安全性 * ----现象 * 多次运行结果 发现输出的hashMap.get(500)和hashMap.get(1500)存在null * 看put源码发现 Hashtable的有关键字synchronized * ----总结 * 多线程时Hashtable是线程安全的,HashMap线程不安全会产生脏数据 */ public static void testHashMapAndHashtable() { final Hashtable<Integer,Integer> hashtable=new Hashtable<Integer, Integer>(); new Thread(new Runnable(){ @Override public void run() { System.out.println("线程0执行"); for(int i=0;i<1000;i++) { hashtable.put(i,i); } System.out.println("线程0------"+hashtable.get(500)); } }).start(); new Thread(new Runnable(){ @Override public void run() { System.out.println("线程1执行"); for(int i=1000;i<2000;i++) { hashtable.put(i,i); } System.out.println("线程1------"+hashtable.get(1500)); } }).start(); final HashMap<Integer,Integer> hashMap=new HashMap<Integer, Integer>(); new Thread(new Runnable() { @Override public void run() { System.out.println("线程2执行"); for(int i=0;i<1000;i++) { hashMap.put(i,i); } System.out.println("线程2-----"+hashMap.get(500)); } }).start(); new Thread(new Runnable(){ @Override public void run() { System.out.println("线程3执行"); for(int i=1000;i<2000;i++) { hashMap.put(i,i); } System.out.println("线程3-----"+hashMap.get(1500)); } }).start(); } /** * -------------测试StringBuilder和StringBuffer的线程安全性 * ----现象 * 多次运行结果 发现输出的builder.length()小于1000,buffer.length()则存在1000 * 看两者append源码发现 StringBuffer的有关键字synchronized * ----总结 * 多线程时StringBuffer是线程安全的,StringBuilder线程不安全会产生脏数据 */ public static void testStrBuilderAndStrBuffer() { StringBuilder builder=new StringBuilder(); StringBuffer buffer=new StringBuffer(); for(int i=0;i<10;i++) { new A(builder,buffer).start(); } } } class A extends Thread{ private StringBuilder builder; private StringBuffer buffer; public A( StringBuilder builder, StringBuffer buffer) { this.builder = builder; this.buffer = buffer; } @Override public void run() { for(int i=0;i<100;i++) { builder.append("c"); buffer.append("c"); try{ Thread.sleep(10); }catch(InterruptedException e) { e.printStackTrace(); } } System.out.println("["+Thread.currentThread().getName()+"]builder:"+builder.length()); System.out.println("["+Thread.currentThread().getName()+"]buffer:"+buffer.length()); } }
-----------------------------------------------------多线程中常用到的 volatile 变量修饰符 使用说明
总结:被volatile修饰的变量是存储在内存(寄存器)中,JVM保证读变量直接从内存(寄存器)中读,他对于所有的线程都是可见性的,每个线程读取值时都会刷新,保证读到的都是最新的值,而非volatile修饰的变量在读写时要从内存拷贝到CPU cache(cpu缓存),每个线程可能在不同的CPU上被处理,这意味着每个线程可以拷贝或者读取到不同的CPU cache中,就可以出现数据的非原子性
package yzp.基础学习.线程相关.资料; /** * Created by Administrator on 2018/7/25 0025. */ public class CalculatePrimes extends Thread { public static final int MAX_PRIMES=1000000; public static final int TEN_SECONDS=10000; public volatile boolean finished=false; public void run(){ /** * 10s内算尽可能 多的素数 * 一个大于1的正整数,如果除了1和它本身以外,不能被其他正整数整除,就叫素数 */ int[] primes=new int[MAX_PRIMES]; int count=0; for(int i=2;count<MAX_PRIMES;i++) { if(finished) { break; } boolean prime=true; for(int j=0;j<count;j++) { if(i%primes[j]==0) { prime=false; break; } } if(prime) { primes[count++]=i; System.out.println("Found prime:"+i); } } } public static void main(String[] args) { CalculatePrimes calculator=new CalculatePrimes(); calculator.start(); try{ Thread.sleep(TEN_SECONDS); }catch(InterruptedException e) { System.out.println("kkkkkkkkkkkkkk"); } calculator.finished=true; } }