多线程_线程的创建02

线程的创建

线程创建的三种方式:

1. 继承Thread类(重点)
  • 自定义线程类继承Thread类
  • 重写run()方法,编写线程执行体
  • 创建线程兑现,调用start()方法启动线程
package com.cnblo.www.ThreadDemo;

/*
  
 */
public class MyThread01  extends Thread {
	//创建线程的方式一:继承Thread类,重新run()方法,调用start开始
      //注意,线程开启不一定立即执行,由CPU调度执行。
	@Override
	public void run() {
		// TODO Auto-generated method stub
		//super.run();
	    //run方法线程体
			for(int i=0;i<=10;i++)
			{
				System.out.println("线程--->"+this.getName()+"当前值"+i);
			}
			
	}
	public static void main(String args[]){
		//创建线程对象
		MyThread01 myt01=new MyThread01();
		//给线程取名
		myt01.setName("小明");
		//调用start()方法线程启动
		myt01.start();
		MyThread01 myt02=new MyThread01();
		myt02.setName("小红");
		myt02.start();
		for  (int a=1;a<=20;a++){			
			System.out.println("当前主线程的值为"+a);
		}
	}

	
}
/*
 * 当前主线程的值为1
线程--->小明当前值0
线程--->小红当前值0
当前主线程的值为2
线程--->小红当前值1
线程--->小明当前值1
线程--->小明当前值2
线程--->小明当前值3
线程--->小明当前值4
线程--->小明当前值5
线程--->小明当前值6
线程--->小明当前值7
线程--->小明当前值8
线程--->小明当前值9
线程--->小明当前值10
线程--->小红当前值2
当前主线程的值为3
当前主线程的值为4
当前主线程的值为5
当前主线程的值为6
当前主线程的值为7
线程--->小红当前值3
当前主线程的值为8
当前主线程的值为9
当前主线程的值为10
当前主线程的值为11
当前主线程的值为12
当前主线程的值为13
当前主线程的值为14
当前主线程的值为15
当前主线程的值为16
当前主线程的值为17
当前主线程的值为18
当前主线程的值为19
当前主线程的值为20
线程--->小红当前值4
线程--->小红当前值5
线程--->小红当前值6
线程--->小红当前值7
线程--->小红当前值8
线程--->小红当前值9
线程--->小红当前值10
 * 
 * */

//经典案例2,网图多线程下载
package com.cnblo.www.ThreadDemo;


import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.commons.io.FileUtils;

import com.sun.org.apache.xml.internal.resolver.helpers.FileURL;

/*
 * 练习Thread多线程,网图下载
 * 
 * */
public class MyThread02 extends Thread {

	private String url;
	private String filename;
	public MyThread02(String b ,String c)
	{
		this.url=b;
		this.filename=c;
		
	}
	@Override
	public void run() {
		
  // TODO Auto-generated method stub
	//super.run();
		DowenLoaderWeb dw=new DowenLoaderWeb();
		dw.dowenloader(url, filename);
		System.out.println(this.getName()+"下载了文件名为:"+filename);
	}
	public static void main(String args[]){
		
		
		MyThread02 t1=new MyThread02("https://psstatic.cdn.bcebos.com/video/wiseindex/aa6eef91f8b5b1a33b454c401_1660835115000.png","图片1");
		MyThread02 t2=new MyThread02("https://psstatic.cdn.bcebos.com/video/wiseindex/aa6eef91f8b5b1a33b454c401_1660835115000.png","图片2");
		MyThread02 t3=new MyThread02("https://psstatic.cdn.bcebos.com/video/wiseindex/aa6eef91f8b5b1a33b454c401_1660835115000.png","图片3");
		//理想状态先t1
		t1.start();
		//理想状态后t2
		t2.start();
		//最后状态后t3
		t3.start();
		
	}

}

/*
 * 
 *  下载..图片3
    Thread-2下载了文件名为:图片3
       下载..图片2
    Thread-1下载了文件名为:图片2
       下载..图片1
    Thread-0下载了文件名为:图片1
//最终结果并不是理想状态,多线程是同步执行,看CPU调度
*/
//下载的类
class DowenLoaderWeb {
	//下载方法
	public void dowenloader(String url,String name){
		
		try {
			FileUtils.copyURLToFile(new URL(url), new File(name));
			System.out.println("下载.."+name);
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println("IO异常dowenloader方法出现问题");
		}
	}
}

2. 实现Runnable接口(重点)
  • 定义MyRunnable类实现Runnable接口
  • 实现run()方法,编写线程执行体
  • 创建线程对象,调用start()方法启动线程。
package com.cnblo.www.runnable;

import com.cnblo.www.ThreadDemo.MyThread01;
//创建线程方式2:实现Runnable接口,重新run()方法,执行线程需要丢人runnable的实现类
public class MyRunnable01 implements Runnable {
    //run()方法的线程体
	public void run() {
	
			for(int i=0;i<=10;i++)
			{
				System.out.println("子线程--->"+"当前值"+i);
				//感觉是run方法中不能再获取线程名字了, Runnable接口里只有个run()方法
			}
			 
	}
	public static void main(String args[]){
	    //创建Runnable的实现类对象
		MyRunnable01 myrunl=new MyRunnable01();
		//创建线程对象,通过线程对象来开启线程
		Thread   t1=new Thread(myrunl);
		 t1.start();//	new Thread(myrunl).satrt();
		for  (int a=1;a<=20;a++){			
			System.out.println("当前主线程的值为"+a);
		}
	}
	
}
/*
当前主线程的值为1
当前主线程的值为2
当前主线程的值为3
子线程--->当前值0
当前主线程的值为4
当前主线程的值为5
当前主线程的值为6
当前主线程的值为7
当前主线程的值为8
当前主线程的值为9
子线程--->当前值1
子线程--->当前值2
子线程--->当前值3
子线程--->当前值4
子线程--->当前值5
子线程--->当前值6
子线程--->当前值7
子线程--->当前值8
子线程--->当前值9
子线程--->当前值10
当前主线程的值为10
当前主线程的值为11
当前主线程的值为12
当前主线程的值为13
当前主线程的值为14
当前主线程的值为15
当前主线程的值为16
当前主线程的值为17
当前主线程的值为18
当前主线程的值为19
当前主线程的值为20

 * */

package com.cnblo.www.runnable;
/*
 * 多个线程同时操作一个资源的情况下,线程不安全
 * 车站买票案例
 * */
public class MyRunnable03  implements Runnable {
    private int coun=10;
    //票数
	@Override
	public void run() 
	{
		// TODO Auto-generated method stub
		
		while(true)
		{
	      if(coun<=0)
	      {
	    	  break;
	       }
	            
	    try {
				Thread.sleep(400);
			} catch (InterruptedException e) 
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        //--
            System.out.println(Thread.currentThread().getName()+"购买到了第"+coun--+"张票!");
		         
		}
		    System.out.println("剩余票数"+coun);
		    
		
	}
    public  static void main(String args[]){
    	
    	MyRunnable03 n1=new MyRunnable03();
    	new Thread(n1,"小红").start();
    	new Thread(n1,"小明").start();
    	new Thread(n1,"小光").start();
    	
    	
    }

}
/*
 * 小红购买到了第10张票!
小明购买到了第8张票!
小光购买到了第9张票!
小明购买到了第7张票!
小光购买到了第6张票!
小红购买到了第7张票!
小明购买到了第4张票!
小光购买到了第3张票!
小红购买到了第5张票!
小红购买到了第2张票!
小光购买到了第1张票!
小明购买到了第0张票!
剩余票数-1
剩余票数-1
剩余票数-1
*/

///经典案例龟兔赛跑
package com.cnblo.www.runnable;
/*
 * 
 * 龟兔赛跑经典案例
 * */
public class MyRunnable05 implements Runnable {
     //判定是否结束
	boolean flags=false;
	//胜利者
	String winner;
	@Override
	
	public void run()
	{
		for (int i=0;i<=100;i++)
		{
			//模拟兔子休息
			if(Thread.currentThread().getName().equals("兔子") &&  i%10==0)
			{
				try {
					Thread.sleep(1);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			//判断比赛是否结束
			 flags=isgameover(i);
			
	         if(flags)
	         {
	        	 break;
	         }	
	         System.out.println(Thread.currentThread().getName()+"奔跑了"+i+"米");
		}
		
			
	}
	//判定是否完成比赛
	public boolean isgameover(int i)
		{
		 if(winner ==null) {
			 //判定如果没有胜利者就继续,如果有,就返回true,结束。
		   if (i>=100)	
		   {	
			  winner=Thread.currentThread().getName();
			  System.out.println("比赛结束!!恭喜获胜者为"+winner);
				return true;
		   }  
			   return false;
		   
		   }
		 return true;
		}
		
		
	public static void main(String args[])
		{
			
		MyRunnable05 load =new MyRunnable05();
		new Thread(load,"乌龟").start();
		new Thread(load,"兔子").start();
		}
		

}
/*
乌龟奔跑了0米
乌龟奔跑了1米
乌龟奔跑了2米
乌龟奔跑了3米
乌龟奔跑了4米
乌龟奔跑了5米
乌龟奔跑了6米
乌龟奔跑了7米
乌龟奔跑了8米
乌龟奔跑了9米
乌龟奔跑了10米
乌龟奔跑了11米
乌龟奔跑了12米
乌龟奔跑了13米
乌龟奔跑了14米
乌龟奔跑了15米
乌龟奔跑了16米
乌龟奔跑了17米
乌龟奔跑了18米
乌龟奔跑了19米
乌龟奔跑了20米
乌龟奔跑了21米
乌龟奔跑了22米
乌龟奔跑了23米
乌龟奔跑了24米
乌龟奔跑了25米
乌龟奔跑了26米
乌龟奔跑了27米
乌龟奔跑了28米
乌龟奔跑了29米
乌龟奔跑了30米
乌龟奔跑了31米
乌龟奔跑了32米
乌龟奔跑了33米
乌龟奔跑了34米
乌龟奔跑了35米
乌龟奔跑了36米
乌龟奔跑了37米
乌龟奔跑了38米
乌龟奔跑了39米
兔子奔跑了0米
乌龟奔跑了40米
兔子奔跑了1米
乌龟奔跑了41米
兔子奔跑了2米
乌龟奔跑了42米
兔子奔跑了3米
乌龟奔跑了43米
兔子奔跑了4米
乌龟奔跑了44米
兔子奔跑了5米
乌龟奔跑了45米
兔子奔跑了6米
乌龟奔跑了46米
兔子奔跑了7米
乌龟奔跑了47米
兔子奔跑了8米
乌龟奔跑了48米
兔子奔跑了9米
乌龟奔跑了49米
乌龟奔跑了50米
乌龟奔跑了51米
乌龟奔跑了52米
乌龟奔跑了53米
乌龟奔跑了54米
乌龟奔跑了55米
乌龟奔跑了56米
乌龟奔跑了57米
乌龟奔跑了58米
乌龟奔跑了59米
乌龟奔跑了60米
乌龟奔跑了61米
乌龟奔跑了62米
乌龟奔跑了63米
乌龟奔跑了64米
乌龟奔跑了65米
乌龟奔跑了66米
乌龟奔跑了67米
乌龟奔跑了68米
乌龟奔跑了69米
乌龟奔跑了70米
乌龟奔跑了71米
乌龟奔跑了72米
乌龟奔跑了73米
乌龟奔跑了74米
乌龟奔跑了75米
乌龟奔跑了76米
乌龟奔跑了77米
乌龟奔跑了78米
乌龟奔跑了79米
乌龟奔跑了80米
乌龟奔跑了81米
乌龟奔跑了82米
乌龟奔跑了83米
乌龟奔跑了84米
乌龟奔跑了85米
乌龟奔跑了86米
乌龟奔跑了87米
乌龟奔跑了88米
乌龟奔跑了89米
乌龟奔跑了90米
乌龟奔跑了91米
乌龟奔跑了92米
乌龟奔跑了93米
乌龟奔跑了94米
乌龟奔跑了95米
乌龟奔跑了96米
乌龟奔跑了97米
乌龟奔跑了98米
乌龟奔跑了99米
比赛结束!!恭喜获胜者为乌龟
*/
3. 实现Callable接口(了解,后期工作中很重要)
  1. 实现Callable接口,需要返回值类型
  2. 重写call方法,需要抛出异常
  3. 创建目标对象
  4. 创建执行服务: ExecutorService ser=Executors.newFixedThreadPool(1);
  5. 提交执行Future result1=ser.submit(t1);
  6. 获取结果:boolean r1=result1.get();
  7. 关闭服务ser.shutdownNow();
package com.cnblo.www.callable;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.commons.io.FileUtils;


//线程创建方式3实现Callable接口
///Callable好处是可以定义返回值
///Callable好处还有可以抛出异常
public class MyCallablDemo01 implements Callable<Boolean> {

	private String url;
	private String name;

	public MyCallablDemo01(String string, String string2) {
		this.url=string;
		this.name=string2;
	}

	public Boolean call() throws Exception {
		DowenLoaderWeb dw=new DowenLoaderWeb();
		dw.dowenloader(url, name);
		return true;
	}

	public static void main(String args[]) throws InterruptedException, ExecutionException {
		
		MyCallablDemo01 t1=new MyCallablDemo01("https://psstatic.cdn.bcebos.com/video/wiseindex/aa6eef91f8b5b1a33b454c401_1660835115000.png","图片1");
		MyCallablDemo01 t2=new MyCallablDemo01("https://psstatic.cdn.bcebos.com/video/wiseindex/aa6eef91f8b5b1a33b454c401_1660835115000.png","图片2");
		MyCallablDemo01 t3=new MyCallablDemo01("https://psstatic.cdn.bcebos.com/video/wiseindex/aa6eef91f8b5b1a33b454c401_1660835115000.png","图片3");
 
		ExecutorService sr=Executors.newFixedThreadPool(3);
	      //创建执行服务
		
		Future<Boolean> rs1=sr.submit(t1);
		Future<Boolean> rs2=sr.submit(t2);
		Future<Boolean> rs3=sr.submit(t3);
		//提交执行
		
		boolean r1=rs1.get();
		boolean r2=rs2.get();
		boolean r3=rs3.get();
		///获取执行结果
		System.out.println(r1);
        System.out.println(r2);
	    System.out.println(r3);
		
		sr.shutdownNow();
		//关闭服务

		
	}
		


	class DowenLoaderWeb {
		
		public void dowenloader(String url,String name){
			
			try {
				FileUtils.copyURLToFile(new URL(url), new File(name));
				System.out.println("下载.."+name);
			} catch (MalformedURLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				System.out.println("IO异常dowenloader方法出现问题");
			}
		}
	}
}

/*
 * 下载..图片1
下载..图片2
下载..图片3
true
true
true
*/

对比差异
  • 继承Thread类
    1. 子类继承Thread类具备多线程能力
    2. 启动线程:子类对象.start();
    3. 不建议使用:避免OOP单继承局限性
  • 实现Runnable接口
    1. 实现Runnable具有多线程能力
    2. 启动线程:传入目标对象+Thread对象.start()
    3. 推荐使用:避免单继承的局限性,灵活方便,方便同一个对象被多个线程使用
posted @ 2025-12-30 10:43  翻滚的小井蛙  阅读(4)  评论(0)    收藏  举报