线程的创建方式:三种方式:
1.通过继承 thread,重写run方法,没有返回值的
/**
* 1.通过继承Thread实现多线程
*/
public class Thread1 extends Thread {
@Override
public void run() {
//业务逻辑
System.out.println();
String str = "通过继承Thread实现多线程";
try {
sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < str.length(); i++) {
//Thread.currentThread() 获取当前线程对象
System.out.print(this.getName() + " " + str.charAt(i));
}
}
}
//调用
public static void main(String[] args) {
for (int i = 0; i <10 ; i++) {
Thread1 t = new Thread1();
t.start();
}
}
2.通过实现 runnable 接口,实现run方法,没有返回值
/**
* 2.通过实现 runnable 来创建多线程
*/
public class Thread2 implements Runnable {
@Override
public void run() {
String str= "通过实现 runnable 来创建多线程";
for (int i = 0; i <str.length() ; i++) {
System.out.println(Thread.currentThread().getName()+" "+str.charAt(i));
}
}
}
public static void main(String[] args) {
//runable
Thread2 t2= new Thread2();
for (int i = 0; i <2 ; i++) {
Thread thread = new Thread(t2);
thread.start();
}
}
以上两种相对来说,实现相对简单 thread 和 runnable的区别 (实际上是基础和接口的区别)
3.callable<V> 实现call方法,有返回值的
import java.util.concurrent.Callable;
/**
* Callable 有返回值的多线程
*/
public class Thread3 implements Callable<Integer> {
private Integer num1;
private Integer num2;
public Thread3(Integer num1,Integer num2){
this.num1=num1;
this.num2=num2;
}
@Override
public Integer call() throws Exception {
return Math.max(num1, num2);
}
}
//调用方法
@Test
public void test() throws Exception {
Thread3 t =new Thread3(55, 111);
FutureTask future = new FutureTask(t);
Thread3 t2 =new Thread3(555, 101);
FutureTask future2 = new FutureTask(t2);
线程池
ExecutorService es = Executors.newScheduledThreadPool(10);
es.submit(future);
es.submit(future2);
es.shutdown();
System.out.println(future.get());
System.out.println(future2.get());
System.exit(0);
}
案例1:
时钟
/**
* 时钟案例
*/
public class ThreadTimeDemo extends Thread {
private SimpleDateFormat sdf ;
public ThreadTimeDemo(String type){
sdf = new SimpleDateFormat(type);
}
@Override
public void run() {
while (true) {
System.out.println(sdf.format(new Date()));
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
//时钟案例
ThreadTimeDemo time = new ThreadTimeDemo("HH:mm:ss");
time.start();
//interrupt 停止状态
Thread1 t = new Thread1();
t.start();
t.interrupt();
}
}
案例2:
火车站售票
/**
* 线程中的具体逻辑:
* 设置总票数 100
* 买票,怎么卖?
* 使用循环进行卖票,每卖出一张,打印被卖出票的信息,总票数执行--操作
* <p>
* 什么时候终止?
* 如果>0才卖票,否则终止
*
* 出现并发问题,怎么解决?(票被重复卖出,多线程并发引起的问题)
* 用同步锁进行解决,线程锁,所有线程持有同一把锁,按顺序执行,作用在出错的业务代码中
* synchronized(线程锁对象){需要顺序处理的业务代码}
*/
public class Ticket extends Thread {
private static int ticketCount = 30;
private static Object obj = new Object();
@Override
public void run() {
while (true) {
if (ticketCount > 0) {
try {
synchronized (obj) {
sleep(1);
}
System.out.println(this.getName() + "当前卖出的票号是:" + ticketCount--);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
System.exit(0);
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
//卖票案例
Ticket ticket = new Ticket();
ticket.start();
Ticket ticket1 = new Ticket();
ticket1.start();
Ticket ticket2 = new Ticket();
ticket2.start();
}
}
多线程下载案例
需求: 多线程下载功能 (网络下载 ) http://mirrors.cn99.com/centos/7.9.2009/isos/x86_64/CentOS-7-x86_64-DVD-2009.iso
下载类
import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
/**
* 多线程下载
* @author wyl
* 通过URL和下载资源建立联系
* 设置参数,读取的范围
* 开始进行文件的读取和写入
* 关闭流
*
*/
public class DownLoad2 extends Thread {
//多线程下载需要的信息
private long startIndex;
private long endIndex;
private int threadId;
private String name;
private static String path="D:\\upload\\";
static {
File file = new File(path);
if(!file.exists()){
file.mkdirs();
}
}
public DownLoad2(long startIndex, long endIndex, int threadId,String name) {
this.startIndex = startIndex;
this.endIndex = endIndex;
this.threadId = threadId;
this.name=name;
}
@Override
public void run() {
long start =System.currentTimeMillis();
try {
//统一资源管理器,可以直接打开网络地址
URL url = new URL(DownLoadTest2.path);//获取资源地址
//因为是基于Http请求,获取httpUrlConnection,获取网络连接对象,和服务器建立联系
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置参数
conn.setRequestMethod("GET");
conn.setConnectTimeout(50000);//连接超时
conn.setReadTimeout(100000);//读取超时
conn.addRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);//设置读取范围
if(conn.getResponseCode()==206) {//部分数据ok
//取出连接中的数据
InputStream is = conn.getInputStream();
//提供一个接收的地方(本地接收)
File file = new File(path+name);
//输出流,开始写数据,随机读写流
RandomAccessFile raf = new RandomAccessFile(file, "rwd");
raf.seek(startIndex);//跳转到线程开始的位置
System.out.println("线程:"+this.getName()+" "+threadId+" 开始的位置:"+startIndex+"---"+" 结束位置"+endIndex);
int i=0;
byte [] buf= new byte[8192];//字节数组,提高读取速度
int len=0;//字节数组读取的长度
while((len=is.read(buf))!=-1) {
System.out.println(this.getName()+" "+(i++));
raf.write(buf, 0, len);
}
raf.close();
is.close();
DownLoadTest2.okThread++;
synchronized (DownLoadTest2.path) {
System.out.println("线程:"+this.getName()+threadId+"下载完毕... "+DownLoadTest2.okThread);
if(DownLoadTest2.okThread==DownLoadTest2.countThread) {
DownLoadTest2.okThread=0;
}
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
long end =System.currentTimeMillis();
System.out.println("线程:"+this.getName()+threadId+"运行时间"+(end - start));
}
}
下载测试类
/**
* 多线程下载测试类
*/
public class DownLoadTest2 {
static String path = "http://mirrors.cn99.com/centos/7.9.2009/isos/x86_64/CentOS-7-x86_64-DVD-2009.iso";
static int countThread=2;//线程数
static int okThread=0;//和线程数有关,记录线程完成的个数
public static String name = "CentOS-7-x86_64-DVD-2009.iso";
public static void main(String[] args) throws Exception {
long start =System.currentTimeMillis();
//统一资源管理器,可以直接打开网络地址
URL url = new URL(DownLoadTest2.path);
//因为是基于Http请求,获取httpUrlConnection,获取网络连接对象,和服务器建立联系
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置参数
conn.setRequestMethod("GET");
conn.setConnectTimeout(50000);//连接超时
conn.setReadTimeout(200000);//读取超时
//判断资源链接是否建立成功,成功进行多线程下载分配
if(conn.getResponseCode()==200) {//成功
//获取文件总长度
long count = conn.getContentLengthLong();
//每个线程下载的大小
long size = count/countThread;
//开启线程进行下载
for (int i = 0; i < countThread; i++) {
long startIndex=size*i;//开始位置 0 102.4
long endIndex=size*(i+1);//结束位置 102.4 204.8
DownLoad2 thread = new DownLoad2(startIndex,endIndex , i,name);
thread.start();
}
}
long end =System.currentTimeMillis();
System.out.println(end-start);
}
}