多线程题

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

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

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();
		    }		
		    
		}	 
	}
}

  

原文地址:https://www.cnblogs.com/javabg/p/7394822.html