zoukankan      html  css  js  c++  java
  • 多线程题

    线程安全问题产生的原因:多个线程在操作共享的数据。

    解决思路;
    就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程时不可以参与运算的。必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。

    synchronized(对象)
    {
          需要被同步的代码 ;
    }

    1、多个窗口同时卖票,保证票数不<=0

    public class MyThread {	 	
    	public static void main(String[] args) throws InterruptedException 
    	{		 
    		Ticket ticket = new MyThread().new Ticket();
    		//共享数据和操作共享数据的方法最好放在一个类中,这样加锁方便
    		for (int i = 0; i < 4; i++) {//开启4个窗口同时卖票
    			new Thread(ticket).start(); 
    		}		 
    	}
    	
    	class Ticket implements Runnable//extends Thread
    	{
    		private  int num = 1000;//操作共享数据
    
    		Object obj = new Object();//只new一次才能保证锁的唯一性
    		public void run()
    		{
    			while(true)
    			{
    				if(num>0)
    				{	
    					synchronized(obj)
    					{
    						if(num>0)
    						{
    							try{Thread.sleep(10);}catch (InterruptedException e){}
    							
    							System.out.println(Thread.currentThread().getName()+".....sale...."+num--);
    						}
    					}
    				}
    			}
    		}
    	}
    }
    

    2、加在方法上的synchronized的区别,加在静态方法上的是当前类名的字节码,加在实例方法上的是当前的实例对象this:  

    	class Test
    {
    synchronized static void sayHello3()//锁为Test.class
    		{
    		
    		}	
    	
    		synchronized void getX(){}//锁为实例化后new t=new Test()的t
    }
    

    3、简述synchronizedjava.util.concurrent.locks.Lock的异同 ?  

    主要相同点:Lock能完成synchronized所实现的所有功能
    主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。Lock还有更强大的功能,

    private class Subtractor implements Runnable
    	{
    		@Override
    		public void run() {
    			// TODO Auto-generated method stub
    			while(true)
    			{
    				/*synchronized (ThreadTest.this) {			
    					System.out.println("j--=" + j--);
    					//这里抛异常了,synchronized 也会自动释放锁 
    				}*/
    				lock.lock();
    				try
    				{
    					System.out.println("j--=" + j--);
    				}finally
    				{
    					lock.unlock();
    //lock不能自动释放锁,所以必须在try-finally中手动释放
    				}
    			}
    		}		
    	}
    

    4、设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1(不考虑增加减少的顺序问题)

    public class TwoThreadNoSequence {
    	public static void main(String[] args) 
    	{
    		final Mydata mydata = new TwoThread().new Mydata();
    		for (int i = 0; i < 2; i++) {
                new Thread(new Runnable() {				
    				@Override
    				public void run() {
    					while(true){
    					   mydata.add();
    					}
    				}
    			}).start();
                new Thread(new Runnable() {				
    				@Override
    				public void run() {
    					while(true){
    					   mydata.sub();
    					}
    				}
    			}).start();
    		}
    	}
    
    	class Mydata
    	{
    		private int j=0;
    		
    		public synchronized void add()
    		{
    			j++;	
    		}
    		
    		public synchronized void sub()
    		{
    			j--;
    		}		
    	}
    }
    

    5、设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1(考虑增加减少的顺序问题,先增加2次,再减少1次)。  

    此题涉及的坑有:

    a、由于是4个线程,所以唤醒机制绝不能是单个唤醒,只能全部唤醒,不然会让其他陷入等待的线程无法获得执行权,程序会陷入死锁  

    b、由于是使用Conditon,所以Condition的使用得在lock方法调用之后,因为其是基于lock实例化出的condition,且使用方法得注意,由于Object上有wait和notify,很容易就会使用到Object上的方法,但是这个和Condition是不搭的,使用错误会报错,Condition上的是await和singal,singalAll

    c、输出两次,得控制代码,千万不要有控制线程的思想,比如多两个加的线程就以为搞定了,这是错误使用多线程,线程执行时机是无须和竞争关系,人为控制不住

    public class TwoThreadSequence {
    	public static void main(String[] args) throws InterruptedException 
    	{
    		final Mydata mydata = new Mydata();
    		for (int i = 0; i < 2; i++) {
                new Thread(new Runnable() {				
    				@Override
    				public void run() {
    					while(true){
    					   mydata.add();
    					}
    				}
    			}).start();
                new Thread(new Runnable() {				
    				@Override
    				public void run() {
    					while(true){
    					   mydata.sub();
    					}
    				}
    			}).start();
    		} 
    	}
    
    	static class Mydata
    	{
    		private int j=0;
    	    Lock lock=new ReentrantLock();
    	    Condition condition = lock.newCondition(); 
    	    boolean flag=false;	    
    		public   void add()
    		{
    			lock.lock();
    			try{
    				while(flag)	//while循环为了防止虚假唤醒		 
    				{
    					try {
    						condition.await();//是await不是wait,wait是和synchronized搭配的
    						//await方法基于lock,所以得位于lock方法调用后面,就如synchronized的锁必须在锁内wait,且是同一把锁
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				} 			
    		 		for (int i = 0; i < 2; i++) {
    					j++;
    					//要控制联系加两次,只能控制数据,千万不要试图去控制线程给你执行两次,那是不现实的,连CPU都无法办到,更何况自己指定线程来连续执行两次
    				}
    				System.out.println("add: "+j); 				  
    				flag=true;				 
    				condition.signalAll();//千万不要调用notify方法,那个是和synchronized搭配的,与condition不搭
    			}
    			finally
    			{
    				lock.unlock();
    			}
    		}
    		
    		public   void sub()
    		{
    			lock.lock();
    			try{
    				while(!flag)				 
    				{
    					try {
    						condition.await();
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				}	 
    				 j--;
    				System.out.println("sub: "+j); 
    				flag=false;				 
    				condition.signalAll();
    			}
    			finally
    			{
    				lock.unlock();
    			}
    		}		
    	}
    }
    

    6、3个线程同时运行,a运行完唤醒c,c运行完唤醒b,b运行完唤醒a,如此往复运行,此题就涉及到多个唤醒条件了  

    public class TwoThreadSequence {
    	public static void main(String[] args) throws InterruptedException 
    	{
    		final Mydata mydata = new Mydata();
    		 
                new Thread(new Runnable() {				
    				@Override
    				public void run() {
    					while(true){
    					   mydata.executeA();
    					}
    				}
    			},"a").start();
                
                new Thread(new Runnable() {				
    				@Override
    				public void run() {
    					while(true){
    					   mydata.executeB();
    					}
    				}
    			},"b").start();
                
                new Thread(new Runnable() {				
    				@Override
    				public void run() {
    					while(true){
    					   mydata.executeC();
    					}
    				}
    			},"c").start();
    	}
    
    	static class Mydata
    	{	 
    		final Lock lock=new ReentrantLock();
    	    final Condition conditionA = lock.newCondition(); 
    	    final Condition conditionB = lock.newCondition(); 
    	    final  Condition conditionC = lock.newCondition(); 
    	    String flag="A";
    		public void executeA() {
    		    lock.lock();
    		    try
    		    {
    			    while(!flag.equals("A"))
    			    {			    	 
    		    		try {
    						conditionA.await();
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}			    	 
    			    }
    				System.out.println(Thread.currentThread().getName()+ "执行了.....");
    				flag="B";
    				conditionB.signalAll();
    		    }
    		    finally
    		    {
    		    	lock.unlock();
    		    }
    		}
    		public void executeB() {
    		    lock.lock();
    		    try
    		    {
    		    	while(!flag.equals("B"))
    			    {			    	 
    		    		try {
    						conditionB.await();
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}			    	 
    			    }
    				System.out.println(Thread.currentThread().getName()+ "执行了.....");
    				flag="C";
    				conditionC.signalAll();				
    		    }
    		    finally
    		    {
    		    	lock.unlock();
    		    }
    		}
    		public void executeC() {
    		    lock.lock();
    		    try
    		    {
    		    	while(!flag.equals("C"))
    			    {			    	 
    		    		try {
    						conditionC.await();
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}			    	 
    			    }
    				System.out.println(Thread.currentThread().getName()+ "执行了.....");
    				flag="A";
    				conditionA.signalAll();
    		    }
    		    finally
    		    {
    		    	lock.unlock();
    		    }		
    		    
    		}	 
    	}
    }
    

      

  • 相关阅读:
    视频: 不抱怨才有今天的马云---励志演讲
    ArcGIS图框工具5.2发布,支持ArcGIS10.0,10.110.2,支持国家2000坐标系
    arcgis 10.2 安装教程(含下载地址)
    delete
    基金销售牌照火热的背后,基金销售牌照、基金支付牌照
    快递业务经营许可证企业信息(截止2016.6.30)
    1月北上广P2P平台之最 平台数成交量现双降
    公募基金牌照:谁在布局?
    delete
    各地互联网小贷牌照申请全揭秘
  • 原文地址:https://www.cnblogs.com/javabg/p/7394822.html
Copyright © 2011-2022 走看看