`

多线程操作

阅读更多
有两个线程,线程a先打印100下,然后线程b打印十下,然后再a打印。。。。

思路:一定要做到线程和任务分离,把a线程的任务和b线程的任务放到一个类里面来,然后再让这两个线程分别调用这个类就可以了

package cn.itcast.heima2;


public class TraditionalThreadCommunication {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		final Business business = new Business();
		new Thread(
				new Runnable() {
					
					@Override
					public void run() {
					
						for(int i=1;i<=50;i++){
							business.sub(i);
						}
						
					}
				}
		).start();
		
		for(int i=1;i<=50;i++){
			business.main(i);
		}
		
	}

}
  class Business {
	  private String executeMethodName ="sub";
	  public synchronized void sub(int i){
		  while(!executeMethodName.equals("sub")){//如果不该我执行
			  try {
				this.wait();//如果不该我执行
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		  }
			for(int j=1;j<=10;j++){
				System.out.println("sub thread sequence of " + j + ",loop of " + i);
			}
			executeMethodName = "main";
		    this.notify();
	  }
	  
	  public synchronized void main(int i){
		  	while(!executeMethodName.equals("main")){//如果不该我执行
		  		try {
					this.wait(); //我就等等
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		  	}
		  	
			for(int j=1;j<=100;j++){
				System.out.println("main thread sequence of " + j + ",loop of " + i);
			}
			
			//令牌标示成sub,并去叫醒sub
			executeMethodName = "sub";
			this.notify();
	  }
  }


如果是三个交替的弄,则可以使用下面的方法,使用wait和notify,那么一共只有一个等待区,如果是使用condition,那么会明确多个等待区,这样不会唤醒不该被唤醒的线程
package cn.itcast.heima2;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ThreeConditionCommunication {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		final Business business = new Business();
		new Thread(
				new Runnable() {
					
					@Override
					public void run() {
					
						for(int i=1;i<=50;i++){
							business.sub2(i);
						}
						
					}
				}
		).start();
		
		new Thread(
				new Runnable() {
					
					@Override
					public void run() {
					
						for(int i=1;i<=50;i++){
							business.sub3(i);
						}
						
					}
				}
		).start();		
		
		for(int i=1;i<=50;i++){
			business.main(i);
		}
		
	}

	static class Business {
			Lock lock = new ReentrantLock();
			Condition conditionMain = lock.newCondition();
			Condition conditionSub2 = lock.newCondition();
			Condition conditionSub3 = lock.newCondition();
		  private String executeMethodName = "main";
		  public  void sub2(int i){
			  lock.lock(); //所只能保证只有一个人能进来,但是不能保证进来的人是谁
			  try{
				  while(!executeMethodName.equals("sub2")){//虽然我抢到了锁,但是如果不是我执行,我还是得等待
					  try {
						conditionSub2.await();//我到2区等待
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				  }
					for(int j=1;j<=10;j++){
						System.out.println("sub2 thread sequence of " + j + ",loop of " + i);
					}
				  executeMethodName="sub3";
				  conditionSub3.signal();
			  }finally{
				  lock.unlock();
			  }
		  }

		  public  void sub3(int i){
			  lock.lock();
			  try{
				  while(!executeMethodName.equals("sub3")){
					  try {
						conditionSub3.await();
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				  }
					for(int j=1;j<=20;j++){
						System.out.println("sub3 thread sequence of " + j + ",loop of " + i);
					}
				 executeMethodName="main";
				  conditionMain.signal();
			  }finally{
				  lock.unlock();
			  }
		  }		  
		  
		  public  void main(int i){
			  lock.lock();
			  try{
				 while(!executeMethodName.equals("main")){
				  		try {
							conditionMain.await();
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
				  	}
					for(int j=1;j<=100;j++){
						System.out.println("main thread sequence of " + j + ",loop of " + i);
					}
					executeMethodName = "sub2";
					conditionSub2.signal();
		  }finally{
			  lock.unlock();
		  }
	  }
	
	}
}



阻塞队列
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class BoundedBuffer {//阻塞队列
   final Lock lock = new ReentrantLock();
   final Condition puterWaitArea  = lock.newCondition(); //放入者等候区
   final Condition takerWaitArea = lock.newCondition(); //消费者等候区

   final Object[] items = new Object[100];  //队列
   int putptr, takeptr, count;

   public void put(Object x) throws InterruptedException {
     lock.lock();//一次只能一个线程进入
     try {
       while (count == items.length)  //线程进入后,查看准入条件
         puterWaitArea.await();
       
       items[putptr] = x;
       if (++putptr == items.length) putptr = 0;
       
       ++count;//转入条件变化
       takerWaitArea.signal();
     } finally {
       lock.unlock();
     }
   }

   public Object take() throws InterruptedException {
     lock.lock();
     try {
       while (count == 0)//线程进入后,查看准入条件
         takerWaitArea.await();
       
       Object x = items[takeptr];
       if (++takeptr == items.length) takeptr = 0;
       
       --count;
       puterWaitArea.signal();
       return x;
     } finally {
       lock.unlock();
     }
   }
 }



---------------------------------------------------------------------------------------------------------------------------------------------------------------------
以上的需求是,多个线程 在某个时刻只能有一个线程进入 其中的一个方法,也就是取东西和放东西 只能有一个操作

下面展示,某一个方法可以同时被多个线程调用,而另一个方法只能被一个线程调用。。生产者消费者问题

package cn.itcast.heima2;

import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockTest {
	public static void main(String[] args) {
		final Queue3 q3 = new Queue3();
		for(int i=0;i<3;i++)
		{
			new Thread(){
				public void run(){
					while(true){
						q3.get();						
					}
				}
				
			}.start();

			new Thread(){
				public void run(){
					while(true){
						q3.put(new Random().nextInt(10000));
					}
				}			
				
			}.start();
		}
		
	}
}

class Queue3{
	private Object data = null;//共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。
	ReadWriteLock rwl = new ReentrantReadWriteLock();
	public void get(){
		rwl.readLock().lock();//只有一个准入条件
		try {
			System.out.println(Thread.currentThread().getName() + " be ready to read data!");
			Thread.sleep((long)(Math.random()*1000));
			System.out.println(Thread.currentThread().getName() + "have read data :" + data);			
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			rwl.readLock().unlock();
		}
	}
	
	public void put(Object data){

		rwl.writeLock().lock();
		try {
			System.out.println(Thread.currentThread().getName() + " be ready to write data!");					
			Thread.sleep((long)(Math.random()*1000));
			this.data = data;		
			System.out.println(Thread.currentThread().getName() + " have write data: " + data);					
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			rwl.writeLock().unlock();
		}
		
	
	}
}


private ReadWriteLock rwl = new ReentrantReadWriteLock();
	public  Object getData(String key){
		rwl.readLock().lock();
		
		Object value = null;
		try{
			value = cache.get(key);
			if(value == null){ //如果没读到,释放读锁,加写锁
				rwl.readLock().unlock();
				
				rwl.writeLock().lock();
				try{
					value = cache.get(key);
					if(value==null){ // 防止重复写,只有value为空的时候才能写,
						//比如有两个线程到了rwl.writeLock().lock();,第一个线程先拿到写锁,写完后,第二个线程就不应该去写了,所以这里对第二个线程要验证下
						value = "aaaa";//实际失去queryDB();
						cache.put(key, value);
					}
				}finally{
					rwl.writeLock().unlock();
				}
				rwl.readLock().lock();
			}
		}finally{
			rwl.readLock().unlock();
		}
		return value;
	}

如果要对等待区进行的数量进行控制,则可以使用CountDownLatch
package cn.itcast.heima2;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CountdownLatchTest {

	public static void main(String[] args) {
		ExecutorService service = Executors.newCachedThreadPool();
		final CountDownLatch cdOrder = new CountDownLatch(1);
		final CountDownLatch cdAnswer = new CountDownLatch(3);		
		for(int i=0;i<3;i++){
			Runnable runnable = new Runnable(){
					public void run(){
					try {
						System.out.println("线程" + Thread.currentThread().getName() + 
								"正准备接受命令");	
						
						cdOrder.await();
						System.out.println("线程" + Thread.currentThread().getName() + 
						"已接受命令");								
						Thread.sleep((long)(Math.random()*10000));	
						System.out.println("线程" + Thread.currentThread().getName() + 
								"回应命令处理结果");						
						cdAnswer.countDown();						
					} catch (Exception e) {
						e.printStackTrace();
					}				
				}
			};
			service.execute(runnable);
		}		
		try {
			Thread.sleep((long)(Math.random()*10000));
		
			System.out.println("线程" + Thread.currentThread().getName() + 
					"即将发布命令");						
			cdOrder.countDown();//这个方法里面有唤醒代码,先把数字减一,如果数字为0则唤醒线程,这相当于对notify的封装,条件被封装到了countDown方法里面,有条件的唤醒
			System.out.println("线程" + Thread.currentThread().getName() + 
			"已发送命令,正在等待结果");	
			cdAnswer.await();
			System.out.println("线程" + Thread.currentThread().getName() + 
			"已收到所有响应结果");	
		} catch (Exception e) {
			e.printStackTrace();
		}				
		service.shutdown();
	}
}


CyclicBarrier 自己的实现,CyclicBarrier就是控制缓冲区中的数目,到了一定的数目才唤醒,await里面会有计数器,当计数器到达指定值则调用notifyAll
package cn.itcast.heima2;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class CyclicBarrierTest {

	public static void main(String[] args) {
		test();
	}
	static int count=0;
	static int step = 1;
	public static void test(){
		ExecutorService service = Executors.newCachedThreadPool();
		final Lock lock = new ReentrantLock();
		
		final Condition con = lock.newCondition();
		for(int i=0;i<3;i++){
			Runnable runnable = new Runnable(){
					public void run(){
						lock.lock();
					try {
						if(step==1){
							System.out.println("线程" + Thread.currentThread().getName() + 
									"即将到达集合地点1,当前已有" + (count+1) + "个已经到达," + (count==2?"都到齐了,继续走啊":"正在等候"));						
							count++;
							if(count<3)
								con.await();
							else{
								count =0 ;
								step =2;
								con.signalAll();
							}
						}
						if(step==2){
							System.out.println("线程" + Thread.currentThread().getName() + 
									"即将到达集合地点2,当前已有" + (count+1) + "个已经到达," + (count==2?"都到齐了,继续走啊":"正在等候"));
							count++;
							if(count<3)
								con.await();
							else{
								count =0 ;
								step =3;
								con.signalAll();
							}
						}
						if(step==3){
						System.out.println("线程" + Thread.currentThread().getName() + 
								"即将到达集合地点3,当前已有" + (count+1) + "个已经到达," + (count==2?"都到齐了,继续走啊":"正在等候"));						
							count++;
							if(count<3)
								con.await();
							else{
								count =0 ;
								step =4;
								con.signalAll();
							}
						}
						lock.unlock();
					} catch (Exception e) {
						e.printStackTrace();
					}				
				}
			};
			service.execute(runnable);
		}
		service.shutdown();
	}
}

分享到:
评论

相关推荐

    java 多线程操作数据库

    一个java 多线程操作数据库应用程序!!!

    易语言多线程操作

    易语言多线程操作源码,多线程操作,子程序1

    QT中sqlite多线程操作4个注意问题

    总结了一下Qt中sqlite多线程操作遇到的几个问题,希望能对有需要的朋友一点帮助 总结了一下Qt中sqlite多线程操作遇到的几个问题,希望能对有需要的朋友一点帮助

    c# 委托访问listbox多线程操作

    此文档提供了一个委托方法,来控制访问listbox,用于多线程操作。c#

    易语言多线程操作模块

    易语言多线程操作模块源码,多线程操作模块,时间_现行时间,互斥锁创建,互斥锁销毁,互斥锁锁定,互斥锁解锁,互斥锁异步锁定,线程启动,线程启动多参,线程创建扩展,线程销毁,线程退出,线程等待,线程强制结束,线程键创建,...

    关于winform使用timer进行多线程操作的例子

    关于winform使用timer进行多线程操作的例子 一个关于网段ping的例子 很好的解释了system.timers.timer的用法

    VB多线程操作

    安全的多线程操作,是VB多线程的不错的选择

    MulThreadSQLiteTest多线程操作数据库

    多线程操作数据库,可解决已加密或者比较复杂的数据库查询时间比较长的问题

    android用jdbc多线程操作sqlite

    之前操作sqlite一直用sdk中的SQLiteOpenHelper,在多线程操作数据库(特别是插入数据)的时候,总是提示sqlite已经被锁定,其它线程就无法继续了。 今天研究了一下android用jdbc操作sqlite,再用多线程去操作数据库的...

    多线程操作窗口源码2012813

    多线程操作窗口源码 功能介绍: 多线程是一种提高程序运行效率和性能的常用技术。 随着我们学习工作的深入,在编程中或多或少会涉及到 需要多线程的情况。多数时候,我们的操作模式是后台 线程中处理数据,计算...

    10个VC 多线程操作实例源代码

    10个VC 多线程操作实例源代码,基本上包含了多线程的方方面面,分别是: 如何安全终止线程 如何创建UI线程 如何创建Worker线程 如何等待线程结束 如何挂起和恢复线程 如何获得线程的退出码 如何使用互斥量 如何使用...

    多线程_按键精灵经典多线程操作_

    按键精灵经典多线程操作,可以套用于任意的其他脚本上

    面试题c++mysql多线程操作系统面试题c++mysql多线程操作系统面试题c++mysql多线程操作系统

    面试题c++mysql多线程操作系统 面试题c++mysql多线程操作系统 面试题c++mysql多线程操作系统 面试题c++mysql多线程操作系统 面试题c++mysql多线程操作系统

    多线程操作窗口源码

    多线程操作窗口源码 功能介绍: 多线程是一种提高程序运行效率和性能的常用技术。 随着我们学习工作的深入,在编程中或多或少会涉及到 需要多线程的情况。多数时候,我们的操作模式是后台 线程中处理数据,计算...

    适合初学者的QT多线程操作的例子

    适合初学者的QT多线程操作的例子 适合初学者的QT多线程操作的例子

    多线程操作实例源码

     多线程的好处在于可以提高CPU的利用率——任何一个程序员都不希望自己的程序很多时候没事可干,在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,这样就大大提高了程序的效率。...

    多线程操作实例源码,,

    多线程操作实例源码 Windows是一个多任务的系统,如果你使用的是windows 2000及其以上版本,你可以通过任务管理器查看当前系统运行的程序和进程。什么是进程呢?当一个程序开始运行时,它就是一个进程,进程所指...

    Android多线程操作

    Android 多线程开发实例,对使用多线程的用户有一定的参考价值!

    [开源]多线程操作模块,包括锁和线程池(非IOCP)[重要].e

    [开源]多线程操作模块,包括锁和线程池(非IOCP)[重要].e

Global site tag (gtag.js) - Google Analytics