20180126:通过Callable实现多线程、生产者-消费者问题、多线程下载(复制)文件

一、通过Callable实现多线程
 1.Callable接口介绍

java.util.concurrent.Callable是一个泛型类接口,其中只有一个call()方法,call()方法会抛出Exception异常, 且返回一个指定的泛型类对象:public V call();


 2.使用Callable接口实现多线程的步骤
 1. 创建Callable接口子类实例化对象.

 2. 创建FutureTask对象,FutureTask也是一个泛型类,且泛型要和Callable的泛型类型相同,

并将Callable对象传入FutureTask的构造方法中(FutureTask是Runnable接口的实现类)

 3. 实例化Thread对象,并在构造方法中传入FutureTask对象

 4. 启动线程.

 用Callable接口实现多线程的使用场景是:一个线程需要另一个线程返回一个值时用到这种方法启动线程

写一个用Callable接口实现多线程的Demo:

package callable;

import java.util.concurrent.Callable;

public class CallableDemo implements Callable<String>{

	//实现Callable泛型类,重写call方法
	public String call() throws Exception {
		String str = Thread.currentThread().getName();
		System.out.println(str+"开始偷袭长安。。。。");
		System.out.println(str+"军路上遇到小股敌军势力。。。");
		return "偷袭成功,不辱使命!";
	}

}
 
package callable;

import java.util.concurrent.FutureTask;

public class RunCallable {
	
	public static void main(String[] args) {
		
		//创建Callable的子类实例化对象
		CallableDemo cd = new CallableDemo();
		//将Callable的子类实例化对象传递
		FutureTask<String> ft = new FutureTask<>(cd);
		
		
		try {
			Thread.currentThread().setName("诸葛亮线程");
			System.out.println(Thread.currentThread().getName()+"开始进军。。。");
			Thread.sleep(2000);
			//将ft对象作为参数传递到Thread对象中
			Thread td = new Thread(ft, "魏延线程");
			td.start();
			//获取子线程的返回值
			System.out.println("报告丞相:"+ft.get());
			System.out.println(Thread.currentThread().getName()+"说:666");
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
	
}
 测试结果为:



 

从上述方法中可以看出:用Callable接口实现的线程类启动仍然靠的是线程类的start()方法,但若想获得线程的返回值,就
FutureTask的对象调用get()方法获得线程的返回对象。


二、生产者-消费者问题

生产者-消费者问题是多线程的一个经典问题,它描述的是生产者线程和消费者线程公用一块缓冲区,生产者是向缓冲区中添加东西,

消费者线程可以从缓冲区取走产品;

解决生产者/消费者问题的方法可以分为两类:

1. 采用某种机制保护生产者和消费者之间的同步;

2. 在生产者和消费者之间建立一个管道。

第一种方式有较高的效率,并且易于实现,代码的可控制性较好,属于常用的模式。

在java中有四种方法支持同步,其中前三个方法是同步方法,一个管道方法,但管道方法不经常用,所以这里就先不讨论:

wait()/notify()、notifyAll()方法;(只讨论这个。。。)

await()/signal()方法;

BlockintQueue阻塞队列方法;

关于wait()/notify()方法

wait()/notify()、notifyAll()方法是父类Object的两个方法:

  • wait(): 当缓冲区已满/空时,生产者/消费者线程停止自己的执行,放弃锁,是自己处于等待状态,让其他线程执行。
  • notify(): 当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程可发出可执行的通知,同时放弃锁,使自己处于等待状态。
 这就是生产者-消费者线程的基本模式,其实和日常生活中的买卖是一样的,生产者生产产品,由于市场作用生 产的产品有上限,消费者不断购买产品,产品没了之后不能购买,但可以提醒生产者继续生产产品去让卖卖继续进行 下去。

接下来写一个同步方法的生产者-消费者Demo:

package con2pro;

public class Producer {
	
	private int count; //设置当前产品数量,初值定为0把
	private final int MAX=5;
	
	
	//写一个生产的方法
	public synchronized void makeProduct(){
		
		try {
			String threadName = Thread.currentThread().getName(); //获得当前线程的线程名
			
			if(count > MAX){
				System.out.println(threadName+"生产的产品达到上限了。。。");
				notifyAll();
				wait();
			}else{
				System.out.println(threadName+"开始生产产品了,");
				count++;
				Thread.sleep(1000);
				System.out.println(threadName+"生产了一件产品,现在产品的数量为:"+count);
				notifyAll();
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}
	
	//写一个消费产品的方法
	public synchronized void buyProduct(){
		
		try {
			String threadName = Thread.currentThread().getName();
			
			if(count <= 0){
				System.out.println(threadName+"产品已售空,请等待生产者生产。。。");
				notifyAll();
				wait();
			}else{
				System.out.println(threadName+"开始购买产品了,");
				count--;
				System.out.println(threadName+"已经购买了产品,当前产品数为:"+count);
				
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}
写一个生产线程和购买线程:

package con2pro;

public class Product implements Runnable{
	
	private Producer pro;
	
	public Product(Producer pro){
		this.pro = pro;
	}
	
	public void run(){
		while(true){
			pro.makeProduct();
		}
	}
	
}

package con2pro;

public class Consumer implements Runnable{
	
	private Producer pro;
	
	public Consumer(Producer pro){
		this.pro = pro;
	}
	
	public void run(){
		while(true){
			pro.buyProduct();
		}
	}
	
}
写一个测试类:

package con2pro;

public class Run {
	
	public static void main(String[] args) {
		
		Producer pro = new Producer();
		
		new Thread(new Product(pro),"卫龙").start();
		new Thread(new Consumer(pro),"薇恩").start();
		new Thread(new Consumer(pro),"德莱厄斯").start();
		
	}
	
}

测试结果如下啊:



三、多线程下载(复制)文件


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值