• java 线程安全不线程不安全


    经常看到一些类,有的说线程安全,有的说线程不安全,顿时懵逼。

    线程安全不安全,主要是在多线程执行的情况下,如果由于线程之间抢占资源而造成程序的bug即为线程不安全,下面就拿arraylist 和Vector来举个例子:

    这里的arraylist 是线程不安全的,Vector是线程安全的

    package Thread;
    
    import java.util.List;
    import java.util.concurrent.CountDownLatch;
    
    public class MyThread  implements Runnable{
    	private List<Object> list;
    	private CountDownLatch countDownLatch;
    	public MyThread(){}
    	public  MyThread(List<Object> list,CountDownLatch countDownLatch){
    		this.list=list;
    		this.countDownLatch=countDownLatch;
    	}
    	@Override
    	public void run() {
    		//给每个线程添加10个元素
    		for(int i=0;i<10;i++){
    			list.add(new Object());
    		}
    		//完成一个子线程
    		countDownLatch.countDown();
    	}
    }
    

      

    package Thread;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Vector;
    import java.util.concurrent.CountDownLatch;
    
    public class ThreadTest {
    	/**
    	 * 这里要比较的是arraylist 和Vector来测试
    	 * arraylist 是线程不安全的
    	 * Vector  线程安全的
    	 * 
    	 */
    	public static void test(){
    		//用来测试的list集合
    		List<Object> list= new ArrayList<Object>();
    		//List<Object> list = new Vector<Object>();
    		//线程数
    		int threadCount =10000;
    		//用来让主线等待thread 个执行完毕
    		CountDownLatch  count=new CountDownLatch(threadCount);
    		for(int i=0;i<threadCount;i++){
    			Thread thread=new Thread(new MyThread(list, count));
    			thread.start();
    		}
    		try {
    			//主线程所有都执行完成后,再向下执行
    			count.await();
    		} catch (InterruptedException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		System.out.println(list.size());
    	}
    	public static void main(String[] args) {
    		for(int i=0;i<10;i++){
    			test();
    		}
    	}
    }
    

     运行结构:

    99995
    99998
    99989
    99973
    99894
    99970
    99974
    99977
    99990
    99989

    当使用Vector时,即把测试的集合换一下

    package Thread;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Vector;
    import java.util.concurrent.CountDownLatch;
    
    public class ThreadTest {
    	/**
    	 * 这里要比较的是arraylist 和Vector来测试
    	 * arraylist 是线程不安全的
    	 * Vector  线程安全的
    	 * 
    	 */
    	public static void test(){
    		//用来测试的list集合
    		//List<Object> list= new ArrayList<Object>();
    		List<Object> list = new Vector<Object>();
    		//线程数
    		int threadCount =10000;
    		//用来让主线等待thread 个执行完毕
    		CountDownLatch  count=new CountDownLatch(threadCount);
    		for(int i=0;i<threadCount;i++){
    			Thread thread=new Thread(new MyThread(list, count));
    			thread.start();
    		}
    		try {
    			//主线程所有都执行完成后,再向下执行
    			count.await();
    		} catch (InterruptedException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		System.out.println(list.size());
    	}
    	public static void main(String[] args) {
    		for(int i=0;i<10;i++){
    			test();
    		}
    	}
    }
    

      这样运行的结果:

    100000
    100000
    100000
    100000
    100000
    100000
    100000
    100000
    100000
    100000

    很明显,使用Vector 这个类运行正确,这就是所谓的线程安全

    当然,这只是代码层面上的,其实多线程不安全,主要因为cpu分配机制,谁获得了cpu谁就能执行,因此造成了线程的不安全.

    我们可以使用synchronized  关键字来同步代码块,达到线程安全:

    下面举个synchronized同步的例子:

    package Thread1;
    
    public class Bank {
    	private int sum = 0;
    
    	public void add(int n) {
    		sum = sum + n;
    		System.out.println("sum= " + sum);
    	}
    }
    
    
    
    package Thread1;
    public class Cus implements Runnable {
    	Bank b = new Bank();
    	@Override
    	public void run() {
    		for (int i = 0; i < 3; i++) {
    			b.add(100);
    		}
    
    	}
    }
    
    
    
    
    
    package Thread1;
    
    public class Test {
    	public static void main(String[] args) {
    		Cus c = new Cus();
    		for (int i = 0; i < 3; i++) {
    			new Thread(c).start();
    		}
    	}
    }
    

      没有使用synchronized修饰的时候,运行结构是:

    sum= 100
    sum= 400
    sum= 500
    sum= 300
    sum= 200
    sum= 600
    sum= 800
    sum= 700
    sum= 900

    当然synchronized 必须要在线程运行的代码块中修饰:

    package Thread1;
    
    public class Bank {
    	private int sum = 0;
    
    	public void add(int n) {
    		sum = sum + n;
    		System.out.println("sum= " + sum);
    	}
    }
    
    
    
    package Thread1;
    public class Cus implements Runnable {
    	Bank b = new Bank();
    	@Override
    	
    	public void run() {
    		synchronized(this){
    			for (int i = 0; i < 3; i++) {
    				b.add(100);
    			}
    		}
    	}
    }
    
    
    
    package Thread1;
    
    public class Test {
        public static void main (String [] args) {
            Cus c = new Cus();
            for(int i=0;i<3;i++){
            	new Thread(c).start();
            }
        }
    }
    

      这样保证,每次只有一个线程在运行,结果为:

    sum= 100
    sum= 200
    sum= 300
    sum= 400
    sum= 500
    sum= 600
    sum= 700
    sum= 800
    sum= 900

    OK,OVER

    每天进步一点点,坚持下去

  • 相关阅读:
    人生是马拉松,胜者不一定是跑得最快的
    二.JSP开发过程中遇到的问题及解决
    一.JSP开发的工具下载与环境搭建
    将文件隐藏到图片中的方法与一键合成工具
    VC6兼容性及打开文件崩溃问题解决
    windows10UWP开发真机调试时遇到DEP6100和DEP6200解决办法
    Vs2015 win10虚拟机启动问题:无法设置UDP端口 解决方法 合集(转载)
    10个维修中最常见的蓝屏代码,值得收藏!
    [idea]添加jar包的方法
    [idea]创建一个控制台程序
  • 原文地址:https://www.cnblogs.com/onfly/p/5820113.html
Copyright © 2020-2023  润新知