多线程
线程包括:线程(Thread),进程(Process),多线程
练习
package com.bilibli.kuangshen.test;
//创建线程方式一:继承Thread类,重写run()方法,调用start开启线程
public class TestThread extends Thread{
@Override
public void run() {
//run方法线程体
for (int i = 0; i < 20; i++) {
System.out.println("我在看代码1111");
}
}
public static void main(String[] args) {
//创建线程对象
TestThread testThread1 = new TestThread();
//调用start()方法开启线程
testThread1.start();;
for (int i = 0; i < 200; i++) {
System.out.println("我在学习多线程");
}
}
}
总结:线程开启不一定执行,由CPU调度执行
练习Thread,实现多线程同步下载图片
package com.bilibli.kuangshen.test;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
//练习Thread,实现多线程同步下载图片
public class TestThread2 extends Thread{
private String url; //网络图片地址
private String name; //保存的文件名
public TestThread2(String url ,String name){
this.url = url;
this.name = name;
}
//下载图片的执行体
@Override
public void run(){
WebDownLoader webDownLoader = new WebDownLoader();
webDownLoader.downloader(url,name);
System.out.println("下载了文件名为" + name);
}
public static void main(String[] args) {
TestThread2 t1 = new TestThread2("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png","1.png");
TestThread2 t2 = new TestThread2("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png","2.png");
TestThread2 t3 = new TestThread2("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png","3.png");
t1.start();
t2.start();
t3.start();
}
}
//下载器
class WebDownLoader{
public void downloader(String url , String name){
try {
FileUtils.copyURLToFile(new URL(url), new File(name));
}catch (IOException e){
e.printStackTrace();
System.out.println("IO异常,downloader方法出现问题");
}
}
}
实现Runnable接口
- 定义MyRunnable类实现Runnable接口
- 实现run()方法,编写线程的执行体
- 创建线程对象,调用start()方法启动线程
主要区别:
小结
使用多个线程操作一个对象
package com.bilibli.kuangshen.test;
//多个线程同时操作一个对象
//买火车票的例子
//发现一个问题:多个线程操作同一个资源的情况下,线程不安全,数据紊乱。(并发问题)
public class TestThread4 implements Runnable{
private int ticketNums = 10;
@Override
public void run(){
while(true){
if (ticketNums <= 0){
break;
}
try{
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "-->拿到了" +ticketNums-- +"票");
}
}
public static void main(String[] args) {
TestThread4 ticket = new TestThread4();
new Thread(ticket,"小明").start();
new Thread(ticket,"老师").start();
new Thread(ticket,"黄牛").start();
}
}
例子:龟兔赛跑
package com.bilibli.kuangshen.test;
//模拟龟兔赛跑
public class Race implements Runnable {
//胜利者
private static String winner;
@Override
public void run(){
for (int i = 0; i <= 1000; i++) {
//模拟兔子休息
if (Thread.currentThread().getName().equals("兔子") && i%50 == 0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//判断比赛是否结束
boolean flag = gameOver(i);
//如果比赛结束了,就停止程序
if(flag){
break;
}
System.out.println(Thread.currentThread().getName()+"-->跑了"+ i + "步" );
}
}
//判断是否完成比赛。
private boolean gameOver( int steps){
//判断是否有胜利者
if (winner != null) {
//已有胜利者。
return true;
}{
if(steps >= 1000){
winner = Thread.currentThread().getName();
System.out.println("Winner is " + winner);
return true;
}
}
return false ;
}
public static void main(String[] args) {
Race race = new Race();
new Thread(race,"乌龟").start();
new Thread(race,"兔子").start();
}
}
实现Callable接口
与Runnable不同的是,Callable需要返回值
- FutureTask类实现了RunnableFuture接口,而RunnnableFuture接口继承了Runnable和Future接口,所以说FutureTask是一个提供异步计算的结果的任务。
- FutureTask可以用来包装Callable或者Runnbale对象。因为FutureTask实现了Runnable接口,所以FutureTask也可以被提交给Executor