工具线程安全量

--------------------------------------------------------------线程安全

就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。 相反地, 

--------------------------------------------------------------线程不安全

就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得的数据是脏数据。

-------------------------------------------------------------字符串和集合的线程安全

从字符串的拼接和读取来看,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 cachecpu缓存),每个线程可能在不同的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;
    }

}

猜你喜欢

转载自www.cnblogs.com/yao-zhen-peng/p/9369499.html