`

多线程操作

阅读更多
有两个线程,线程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多线程操作数据库:深入解析与应用 在当今高度并发的应用环境中,Java多线程技术被广泛应用于处理数据库操作,以提升系统的响应速度和处理能力。本文将基于一个具体的Java多线程操作数据库的应用程序,深入...

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

    ### QT中sqlite多线程操作4个注意问题 在开发基于Qt的应用程序时,经常会遇到需要使用多线程来进行SQLite数据库操作的情况。然而,多线程环境下的数据库操作相较于单线程来说更为复杂,需要特别注意一些细节问题,...

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

    ### C# 委托访问 ListBox 的多线程操作 #### 概述 在 C# 编程语言中,为了确保界面的响应性并避免在执行长时间运行的任务时导致用户界面(UI)冻结,通常会采用多线程技术来处理后台任务。在本案例中,介绍了一种...

    易语言多线程操作

    在易语言中实现多线程操作是提高程序性能、优化资源利用的重要手段。多线程是指一个程序内同时执行多个独立的线程,每个线程都有自己的执行序列,可以并发执行不同的任务。 在易语言中进行多线程操作,主要涉及以下...

    VB多线程操作

    在VB(Visual Basic)编程环境中,多线程操作是一个关键的概念,它允许程序同时执行多个独立的任务,从而提高应用程序的效率和响应性。在标题"VB多线程操作"中,我们聚焦的是如何在VB中实现和管理多线程。 多线程在...

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

    本例子重点介绍了如何利用`System.Timers.Timer`组件来实现这样的多线程操作,特别是针对网段ping功能的实现。`System.Timers.Timer`是一个异步定时器,它在单独的线程上触发`Elapsed`事件,避免了阻塞UI线程。 ...

    MulThreadSQLiteTest多线程操作数据库

    总之,多线程操作SQLite数据库是提升应用性能的有效手段,但同时也需要谨慎处理线程安全、连接管理、事务控制等问题。通过合理的设计和优化,我们可以充分利用多线程的优势,实现高效、稳定的数据库操作。

    Android多线程操作

    标题"Android多线程操作"和描述"Android多线程开发实例,对使用多线程的用户有一定的参考价值!"暗示我们将深入探讨Android中的线程管理以及如何在实践中有效利用。 Android系统默认运行在主线程,也被称为UI线程,...

    Android多线程操作sqlite(Sqlite解决database locked问题)

    本文将深入探讨如何在Android中使用多线程操作SQLite并解决数据库被锁定的问题。 首先,理解“database locked”的原因。SQLite采用独占式锁定策略,这意味着当一个事务正在进行时,其他试图访问同一数据库的事务会...

    易语言多线程操作模块

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

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

    标题“多线程_按键精灵经典多线程操作_”表明我们将探讨的是如何在按键精灵这款自动化工具中实现多线程的功能。按键精灵是一款功能强大的自动化软件,它可以模拟用户的键盘和鼠标操作,执行一系列预定义的任务,如...

    android用jdbc多线程操作sqlite

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

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

    对于初学者来说,理解和掌握QT中的多线程操作至关重要。 在QT中,多线程主要用于将耗时的操作(如大数据处理、网络通信、数据库操作等)与用户界面的更新分离开来,以避免阻塞UI,提高用户体验。QT提供了QThread类...

    多线程操作窗口源码2012813

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

    多线程操作串口示例(带modbus

    本示例结合了这两个概念,展示了如何在编程中实现多线程操作串口,特别是与Modbus协议交互。 首先,我们要理解多线程。在计算机科学中,线程是程序执行的基本单元,每个线程可以独立地执行任务。多线程意味着一个...

    多线程操作系统:并行计算的基石

    多线程操作系统是现代计算机系统中的一个关键概念,它允许多个线程并行执行,从而提高了程序的执行效率和系统的响应速度。本文将详细介绍多线程操作系统的工作原理、优势、实现方式,并提供Python代码示例来演示多...

    多线程操作共享文件.zip

    在IT领域,多线程操作共享文件是一项关键的技术,尤其在并发编程中。Delphi作为一款强大的面向对象的 Pascal 编程环境,提供了丰富的工具和类库来支持这样的任务。本压缩包“多线程操作共享文件.zip”显然是一个关于...

Global site tag (gtag.js) - Google Analytics