Java基础之线程(三)

一、通过Callable接口实现多线程

1、Callable接口介绍

java.util.concurrent.Callable是一个泛型接口,只有一个call()方法;

call()方法抛出Exception异常,且返回一个指定的泛型类的对象

2、Callable接口实现线程的应用场景

当父线程想获取子线程的运行结果时

3、使用Callable接口实现多线程的步骤

第一步:创建Callable子类的实例化对象;

第二步:创建FutureTask对象,并将Callable对象传入FutureTask的构造方法中(注意:FutureTask实现了Runnable接口和Future接口);

第三步:实例化Thread对象,并在构造方法中传入FutureTask对象;

第四步:启动线程。

二、生产者-消费者问题

生产者线程不断生产,消费者线程不断取走生产者生产的产品。

Object中的几个方法支持:

wait():线程等待,当前线程进入调用对象的线程等待池

notify():唤醒一个等待线程

notifyAll():唤醒全部等待的线程

注意:以上三个方法都必须在同步机制中调用

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

使用RandomAccessFile与InputStream的skip(long n)方法使每个线程负责文件的每一部分读写。


Callable实现多线程实例:

package callable;

import java.util.concurrent.Callable;

public class GeneralCallable implements Callable<String>{

	@Override
	public String call() throws Exception {
		String threadName = Thread.currentThread().getName();
		System.out.println(threadName + "开始偷袭...");
		System.out.println(threadName + "与小股敌人作战");
		return "偷袭成功!";
	}

}
package callable;

import java.util.concurrent.FutureTask;

public class CallableDemo {

	public static void main(String[] args) {
		//创建Callable子类的实例化对象
		GeneralCallable call = new GeneralCallable();
		//创建FutureTask对象,并将Callable对象传入FutureTask构造方法中
		FutureTask<String> task = new FutureTask<String>(call);
		//实例化Thread对象,并在构造方法中传入FutureTask对象
		Thread t = new Thread(task,"魏延线程");
		t.start();//启动线程
		System.out.println(Thread.currentThread().getName() + "进入休眠状态(休眠5秒钟)...");
		try {
			Thread.sleep(5000);
			String report = task.get();//获取子线程的返回值
			System.out.println("子线程返回的结果是:" + report);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
运行结果:


生产者-消费者(一对一)实例:

package OneToOne.producer;

//早餐基础类
public class Breakfast {
	private String food;//吃的
	private String drink;//喝的
	private boolean flag = false;
	
	public synchronized void makeBreakfast(String food,String drink) {
		if(flag) {
			try {
				wait();//生产者线程进入同步对象维护的“线程等待池”
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.food = food;
		try {
			Thread.sleep(1000);//休眠,但不释放“锁”
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.drink = drink;
		flag = true;
		notify();
	}
	
	public synchronized void eatBreakfast() {
		if(!flag) {
			try {
				wait();//消费者线程进入同步对象维护的“线程等待池”,而且当前线程释放“锁”
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(this.food + "-------------->" + this.drink);
		flag = false;
		notify();
	}
}
package OneToOne.producer;

//生产者线程
public class Producer implements Runnable {
	private Breakfast bf;
	
	public Producer(Breakfast bf) {
		this.bf = bf;
	}
	
	@Override
	public void run() {
		for(int i = 1;i <= 7; i++) {
			if(i % 2 == 0) {
				this.bf.makeBreakfast("bread","milk");
			}else {
				this.bf.makeBreakfast("馒头","稀饭");
			}
		}

	}

}
package OneToOne.producer;

//消费和线程
public class Consumer implements Runnable {
	private Breakfast bf;
	
	public Consumer(Breakfast bf) {
		this.bf = bf;
	}
	@Override
	public void run() {
		for(int i = 1; i <= 7; i++) {
			this.bf.eatBreakfast();
		}
	}

}
package OneToOne.producer;

public class Test {

	public static void main(String[] args) {
		Breakfast bf = new Breakfast();
		new Thread(new Producer(bf)).start();
		new Thread(new Consumer(bf)).start();
	}

}
运行结果:


生产者-消费者(多对多)实例:

package ManyToMany;

public class Product {
	private int count = 0;
	private final int MAX = 5;//最大库存量
	
	//生产商品
	public synchronized void makeProduct() {
		String threadName = Thread.currentThread().getName();
		if(count >= MAX) {
			System.out.println("货物已满" + threadName + "停止生产");
			try {
				notifyAll();//每生产一个商品,则通知(唤醒)所有等待着的消费者线程
				wait();//生产者线程等待
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}else {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			count++;//模拟生产
			System.out.println(threadName + "生产了商品,目前商品总量:" + count);
			notifyAll();
		}
	}
	
	public synchronized void buyProduct() {
		String threadName = Thread.currentThread().getName();
		if(count <= 0) {
			System.out.println(threadName + "已无货,请等待...");
			notifyAll();//通知所有生产者线程
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}else {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			count--;//模拟买商品
			System.out.println(threadName + "买了一件商品,当前剩余商品数:" + count);
		}
	}
}
package ManyToMany;

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

}
package ManyToMany;

public class Consumer implements Runnable {

	private Product product;
	public Consumer(Product product) {
		this.product = product;
	}
	@Override
	public void run() {
		while(true) {
			product.buyProduct();;
		}
	}

}
package ManyToMany;

public class Test {

	public static void main(String[] args) {
		Product pro = new Product();
		new Thread(new Producer(pro),"1号生产者").start();//启动1号生产者
		new Thread(new Producer(pro),"2号生产者").start();//启动2号生产者
		new Thread(new Consumer(pro),"消费者A").start();//启动消费者A
		new Thread(new Consumer(pro),"消费者B").start();//启动消费者B
	}

}
运行结果:



多线程下载(复制)文件实例:

package download;

import java.io.*;

public class DownloadRunnable implements Runnable {
	private File srcFile;//源文件路径
	private long startPos;//每个线程开始下载的位置
	private long partTask;//每个线程的下载任务
	private RandomAccessFile raf;//用来写入
	
	
	public DownloadRunnable(File srcFile, long startPos, long partTask, RandomAccessFile raf) {
		super();
		this.srcFile = srcFile;
		this.startPos = startPos;
		this.partTask = partTask;
		this.raf = raf;
	}

	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName() + "准备从第" + startPos + "个字节开始读...");
		InputStream input = null;
		try {
			input = new FileInputStream(srcFile);
			input.skip(startPos);//跳过输入流的startPos个字节
			byte[] b = new byte[1024*10];
			int len = 0;
			int count = 0;//用来记录已经读写的字节数
			while((len = input.read(b)) != -1 && count < partTask) {
				raf.write(b, 0, len);
				count += len;
			}
			System.out.println(Thread.currentThread().getName() + "已经写入了" + count + "个字节");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				input.close();
				raf.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

}
package download;

import java.io.*;

public class Client {

	public static void main(String[] args) throws Exception {
		File srcFile = new File("f:" + File.separator + "Future World Music - Dream Chasers.wav");
		long partTask = srcFile.length() / 6; //准备使用6个线程,计算每个线程的下载任务
		for(int i = 0;i < 6;i++) {
			RandomAccessFile raf = new RandomAccessFile("d:" + File.separator + srcFile.getName(),"rw");
			long startPos = i * partTask;//计算每条线程读写的起始位置
			raf.seek(startPos);//设置每条线程的文件指针偏移量
			new Thread(new DownloadRunnable(srcFile,startPos,partTask,raf)).start();
		}
	}

}
运行结果:








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
疫情居家办公系统管理系统按照操作主体分为管理员和用户。管理员的功能包括办公设备管理、部门信息管理、字典管理、公告信息管理、请假信息管理、签到信息管理、留言管理、外出报备管理、薪资管理、用户管理、公司资料管理、管理员管理。用户的功能等。该系统采用了MySQL数据库,Java语言,Spring Boot框架等技术进行编程实现。 疫情居家办公系统管理系统可以提高疫情居家办公系统信息管理问题的解决效率,优化疫情居家办公系统信息处理流程,保证疫情居家办公系统信息数据的安全,它是一个非常可靠,非常安全的应用程序。 管理员权限操作的功能包括管理公告,管理疫情居家办公系统信息,包括外出报备管理,培训管理,签到管理,薪资管理等,可以管理公告。 外出报备管理界面,管理员在外出报备管理界面中可以对界面中显示,可以对外出报备信息的外出报备状态进行查看,可以添加新的外出报备信息等。签到管理界面,管理员在签到管理界面中查看签到种类信息,签到描述信息,新增签到信息等。公告管理界面,管理员在公告管理界面中新增公告,可以删除公告。公告类型管理界面,管理员在公告类型管理界面查看公告的工作状态,可以对公告的数据进行导出,可以添加新公告的信息,可以编辑公告信息,删除公告信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值