• JAVA 并发----记录1


    package com.shob.syn;
    
    public class SharaData {
    
    	private static int count = 0;
    	
    	/**
    	 * 并发测试
    	 * 共享性:多线程下共享数据问题
    	 */
    	private static void sha(){
    		final SharaData data = new SharaData();
    		for (int i = 0; i < 10; i++) {
    			new Thread(new Runnable() {
    				
    				@Override
    				public void run() {
    					try {
    	                        //进入的时候暂停1毫秒,增加并发问题出现的几率
    	                    Thread.sleep(1);
    					} catch (InterruptedException e) {
    	                    e.printStackTrace();
    	                }
    					for (int j = 0; j < 100; j++) {
    						data.add();
    					}
    					
    					System.out.println(count+"  ");
    				}
    			}).start();
    		}
    		
    		 try {
    	            //主程序暂停3秒,以保证上面的程序执行完成
    	         Thread.sleep(3000);
    	     } catch (InterruptedException e) {
    	         e.printStackTrace();
    	     }
    	     System.out.println("count=" + count);
    	}
    	
    	
    	/**
    	 * 并发测试
    	 * 互斥性:同时只允许一个访问者对其进行访问,具有唯一性和排它性
    	 * 通常我们允许多个线程对数据进行读操作,但是同一时间只允许一个线程对数据进行写操作
    	 * 这种通常叫为共享锁和排它锁,或者读锁和写锁。
    	 * 如果资源不具有互斥性,也不需要担心线程安全。
    	 * 对于不可变的数据共享,所有线程都只能对其进行读操作,所以不用考虑线程安全问题。
    	 * 但是对共享数据的写操作,一般就需要保证互斥性
    	 */
    	private static void shasyn(){
    		final SharaData data = new SharaData();
    		for (int i = 0; i < 10; i++) {
    			new Thread(new Runnable() {
    				
    				@Override
    				public void run() {
    					try {
    	                        //进入的时候暂停1毫秒,增加并发问题出现的几率
    	                    Thread.sleep(1);
    					} catch (InterruptedException e) {
    	                    e.printStackTrace();
    	                }
    					for (int j = 0; j < 100; j++) {
    						data.addsyn();
    					}
    					
    					System.out.println(count+"  ");
    				}
    			}).start();
    		}
    		
    		 try {
    	            //主程序暂停3秒,以保证上面的程序执行完成
    	         Thread.sleep(3000);
    	     } catch (InterruptedException e) {
    	         e.printStackTrace();
    	     }
    	     System.out.println("count=" + count);
    	}
    	
    	private void add(){
    		count++;
    	}
    	
    	private synchronized void addsyn(){
    		count++;
    	}
    	
    	/**
    	 * 原子性:指对数据的操作是一个独立的、不可分割的整体。换句话说,就是一次操作,是一个连续不可中断的过程
    	 * 数据不会执行一半的时候被其他线程所修改。
    	 * 保证原子性的最简单方式是操作系统指令,就是说如果一次操作对应一条操作系统指令,这样肯定能保证原子性。
    	 * 但是很多操作不能通过一条指令来完成。
    	 * 
    	 * 例如:long类型的运算,很多系统需要分成多条指令分别对高位和低位进行操作才能完成。
    	 * 还比如,我们经常使用的整数 i++ 的操作,其实需要分成三个步骤:
    	 * (1)读取整数 i 的值;(2)对 i 进行加一操作;(3)将结果写回内存。 
    	 */
    	private void oi(){
    		/**
    		 * 对于这种组合操作,要保证原子性,最常见的方法就是加锁。如Synchronized or Lock
    		 * 
    		 * 除了锁以外,还有一种方式就是CAS(Compare And Swap),
    		 * 即修改数据之前先比较与之前读取到的值是否一致,如果一致,则进行修改,如果不一致则重新执行。
    		 * 这也是乐观锁的实现原理。
    		 * 
    		 * 不过CAS在某些场景下不一定有效,比如另一线程先修改了某个值,然后再改回原来值,这种情况下,CAS是无法判断的。
    		 */
    	}
    	
    	//-----------------------------------------------------------------------------------
    	
    	/**
    	 * 可见性:
    	 */
    	private void see(){
    		/**
    		 * 每个线程都有一个自己的工作内存(相当于CPU高级缓冲区,这么做的目的还是在于进一步缩小存储系统与CPU之间速度的差异,提高性能),
    		 * 对于共享变量,线程每次读取的是工作内存中共享变量的副本,写入的时候也直接修改工作内存中副本的值,
    		 * 然后在某个时间点上再将工作内存与主内存中的值进行同步。
    		 * 这样导致的问题是,如果线程1对某个变量进行了修改,线程2却有可能看不到线程1对共享变量所做的修改。
    		 */
    	}
    	
    	/**
    	 * jvm 内存模型
    	 */
    	private void jvm(){
    		/**
    		 * 
    		 * 	    线程一				       线程二
    		 * 		||					  ||
    		 * 		||					  ||			
    		 * 		V					  V	
    		 *  线程一工作内存		 线程二工作内存
    		 *  共享变量副本			 共享变量副本
    		 *  	||						||
    		 *  	||						||
    		 *  	V						V
    		 *   共享变量	                         共享变量
    		 *  			    主内存
    		 * 
    		 */
    		
    	}
    	
    	private static boolean ready;//默认false
    	
        private static int number;
        
    	private static class ReaderThread extends Thread {
            public void run() {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (!ready) {
                    System.out.println(ready);
                }
                System.out.println(number);
            }
        }
     
        private static class WriterThread extends Thread {
            public void run() {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                number = 100;
                ready = true;
            }
        }
    	
        
        /**
         * 有序性:为了提高性能,编译器和处理器可能会对指令做重排序。
         * 重排序可分为三种:
         * 1、编译器优化的重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
         * 2、指令级并行的重排序。现代处理器采用了指令级并行技术(Instruction-Level Parallelism, ILP)来将多条指令重叠执行。
         * 如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。
         * 3、内存系统的重排序。由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。
         * Java 中也可通过Synchronized或Volatile来保证顺序性。
         * @param args
         */
        private void xu(){
        	
        }
    	
    	public static void main(String[] args) {
    		//shasyn();
    		
    		//偶尔会出线打印true 100
    		/**
    		 * 当然,这个结果也只能说是有可能是可见性造成的,当写线程(WriterThread)设置ready=true后,
    		 * 读线程(ReaderThread)看不到修改后的结果,所以会打印false,
    		 * 对于第二个结果,也就是执行if (!ready)时还没有读取到写线程的结果,但执行System.out.println(ready)时读取到了写线程执行的结果。
    		 * 不过,这个结果也有可能是线程的交替执行所造成的。
    		 * Java 中可通过Synchronized或Volatile来保证可见性,
    		 */
    		new WriterThread().start();
    		new ReaderThread().start();
    	}
    }
    

     

  • 相关阅读:
    第二周 历年学生作品评论
    第二周 WBS、NABCD查阅
    第二周 SCRUM站立会议
    第二周 燃尽图
    第二周 对读构建之法后提出的五个问题
    补上一周的进度条
    词频统计
    每周进度及工作量统计——第三周
    第三周 四人小组
    词频统计 效能分析
  • 原文地址:https://www.cnblogs.com/binbang/p/6370277.html
Copyright © 2020-2023  润新知