继承Thread类
//1.继承Thread类 2.重写run()方法 3.调用start()方法开启线程
public class testThread1 extends Thread{
@Override
public void run() {
//run 方法流程体
for (int i = 0; i < 10; i++) {
System.out.println("====================");
}
}
public static void main(String[] args) {//main 线程,主线程
//start 方法开启线程
testThread1 testThread1 = new testThread1();
testThread1.start();
for (int i = 0; i < 1000; i++) {
System.out.println("----------------------------------");
}
}
}
分析:当多线程没有开启时,代码只执行主线程里面的main里面的代码,当开启后,线程开启后不一定立即执行,根据CPU调度
运行结果:
实现runnable接口
- 实现runnable接口
- 重写run方法
- 创建线程,用线程实现start 方法
- 一般建议使用runnable接口
//创建线程,实现 runnable接口,重写run 方法,执行线程需要丢入runnable接口实现类
public class testThread3 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println("我在看代码"+i);
}
}
public static void main(String[] args) {
//创建runnable接口的实现对象
testThread3 testThread3 = new testThread3();
//创建线程对象,通过线程对象来开启我们的线程,相当于代理
//Thread thread = new Thread(testThread3);
//thread.start();这两句和 new Thread(testThread3).start();意思相同
new Thread(testThread3).start();
for (int i = 0; i < 100; i++) {
System.out.println("shmily"+i);
}
}
}
与thread不同之处是:
- Thread直接new一个类,用这个类直接开启这个线程
- runnable使用new一个这个类,在new一下Thread,之后在start,一般建议用Runnable方法
案例:网图下载
- 下载类,类里面写方法包括地址和名字
- 继承Thread类,构造器写地址和名字
- 重写run方法,run方法里面写下载类里面的东西
- 在主函数里面用start的方法开启线程
举例:
//练习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 thread2 = new testThread2("https://csdnimg.cn/feed/20200423/bb8e24713d67af32f82c5a4ffacd043f.jpg","2.jpg");
thread2.start();
}
}
//下载器
class WebDownLoader {
//下载方法
public void downLoader(String url,String name ) {
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果:
多个线程同时操作一个对象
1.多个线程操作同一个线程对象,会出现紊乱现象,一个票可能会出现多个人拿到,由于票数较少,所以添加了时间延时功能,
2.Thread.currentThread().getName()拿到名字
//多个线程同时操作同一个对象
//买火车票的例子
public class testThread4 implements Runnable{
private int ticketNums=10;
@Override
public void run() {
while (true){
if (ticketNums<=0){
break;
}
//模拟延时
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"拿到了第"+ticketNums--+"票");
}
}
public static void main(String[] args) {
testThread4 testThread4 = new testThread4();
new Thread(testThread4,"小明").start();
new Thread(testThread4,"老师").start();
new Thread(testThread4,"黄牛").start();
}
}
运行结果为:
龟兔赛跑例子
- 首先来个赛道距离,然后要离终点越来越近
- 判断比赛是否结束
- 打印出胜利者
- 龟兔赛跑开始
- 故事中是乌龟赢了,兔子需要睡觉,所以我们来模拟兔子睡觉
- 终于,乌龟赢得比赛
public class Race implements Runnable{
private static String winner;
@Override
public void run() {
for (int i = 0; i <=100; i++) {
//模拟兔子休息
if (Thread.currentThread().getName().equals("兔子") && i%10==0){
try {
Thread.sleep(5);
} 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>=100){
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接口
- 实现callable接口,需要返回值类型
- 重写call方法,需要抛出异常
- 创建目标对象
- 创建执行服务: ExecutorService ser=Executors.newFixedThreadPool(1);
- 提交执行: Future result1 = ser.submit(t1);
- 获取结果: boolean r1 = result1 .get()
- 关闭服务: ser.shutdownNow();
//callable中的返回值类型和call方法中的返回值保持一致
public class testCallable implements Callable<Boolean> {
private String url;//网络图片的地址
private String name;//保存的文件名
//构造器
public testCallable(String url,String name){
this.url=url;
this.name=name;
}
@Override
public Boolean call() {
WebDownLoader webDownLoader = new WebDownLoader();
webDownLoader.downLoader(url,name);
System.out.println("下载了的文件名:"+name );
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
testCallable t1 = new testCallable("https://csdnimg.cn/feed/20200423/bb8e24713d67af32f82c5a4ffacd043f.jpg","2.jpg");
testCallable t2 = new testCallable("https://csdnimg.cn/feed/20200423/bb8e24713d67af32f82c5a4ffacd043f.jpg","1.jpg");
//创建执行服务:后边的数字表示有几个线程就是几
ExecutorService ser = Executors.newFixedThreadPool(2);
//提交执行:
Future<Boolean> r1 = ser.submit(t1);
Future<Boolean> r2 = ser.submit(t2);
// 获取结果:
boolean rs1 = r1.get();
boolean rs2 = r2.get();
System.out.println(rs1);
System.out.println(rs2);
//关闭服务:
ser.shutdownNow();
}
}
//下载器
class WebDownLoader {
//下载方法
public void downLoader(String url,String name ) {
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
}
}
}
线程创建的三种方式:Thread类,Runnable接口和Callable接口