JAVA多线程——创建线程的方式

JAVA多线程——创建线程

继承Thread类

  • 自定义一个线程类继承Thread类
  • 重写run方法,编写线程执行体
  • 创建线程对象,调用start()方法启动线程
  • 不建议使用,java是单继承有局限性
package com.peng.demon01;


import javax.swing.*;

//创建线程方式一:继承Threaf类,重写run方法,调用start开启线程
public class TestThread01 extends Thread{
    
    
    @Override
    public void run() {
    
    
        //线程体
        for (int i = 0; i < 100; i++) {
    
    
            System.out.println("打王者荣耀"+i);
        }
    }
    public static void main(String[] args) {
    
    //main()线程,主线程
        
        //开启另外一个线程
        //创建一个线程对象
        TestThread01 testThread01 = new TestThread01();

        //调用start开启线程
        testThread01.start();//start()方法的作用:1,启动当前线程  2,调用当前线程的run()方法
        
        for (int i = 0; i < 1000; i++) {
    
    //由主线程运行
            System.out.println("不要打英雄联盟"+i);
        }
    }
}

在这里插入图片描述

两个线程交替执行

线程开启并不一定立即执行,由CPU调度执行

用多线程实现下载网图

package com.peng.demon01;


import org.apache.commons.io.FileUtils;

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

//实现多线程同步下载图片
public class TestThread02 extends Thread{
    
    
   private String url;//地址
   private String name;//图片名
    // 构造器
    public TestThread02(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) {
    
    
        //线程体
        //创建线程对象
        TestThread02 testThread01 = new TestThread02("http://www.xinhuanet.com/photo/2020-08/26/1126412315_15983723897731n.jpg",",新华网图片1.jpg");
        TestThread02 testThread02 = new TestThread02("http://www.xinhuanet.com/photo/2020-08/26/1126412315_15983723898911n.jpg",",新华网图片2.jpg");
        TestThread02 testThread03 = new TestThread02("http://www.xinhuanet.com/photo/2020-08/25/1126412104_15983627450851n.jpg",",新华网图片3.jpg");
        TestThread02 testThread04 = new TestThread02("http://www.xinhuanet.com/photo/2020-08/25/1126412104_15983627451171n.jpg",",新华网图片4.jpg");

        //启动线程
        testThread01.start();
        testThread02.start();
        testThread03.start();
        testThread04.start();
    }
}
//下载器
class WebDownloader{
    
    
    //下载方法
    public void downloader(String url,String name){
    
    
        try {
    
    //捕获异常
         // FileUtils是一个工具类,copyURLToFile是一个方法,方法的作用是把网络资源的地址变成文件
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
    
    
            e.printStackTrace();
            System.out.println("IO异常,downloader方法出现问题");
        }
    }
}

在这里插入图片描述

创建Thread匿名子类的方式也可以创建线程

package com.work;

//继承Thread类创建线程
public class Work1 {
    
    
    public static void main(String[] args) {
    
    
        new Thread(){
    
    
            @Override
            public void run() {
    
    

                for (int i = 0; i <100 ; i++) {
    
    
                    if (i % 2==0){
    
    
                        System.out.println(Thread.currentThread().getName() +" " +i);
                    }

                }
            }
        }.start();

        new Thread(){
    
    
            @Override
            public void run() {
    
    

                for (int i = 0; i <100 ; i++) {
    
    
                    if (i % 2!=0){
    
    
                        System.out.println(Thread.currentThread().getName()+" " +i);
                    }

                }
            }
        }.start();
    }
}


Thread类有关的常用方法

start():启动线程,并执行对象的run()方法

run() :线程在被调度时执行的操作

currentThread():静态方法,返回执行当前代码的线程

getName():获取当前线程的名字

setName():设置当前线程的名字

利用构造方法也可以给线程命名

在这里插入图片描述

yield():释放CPU的执行权

join():如果在线程A中调用B线程的join(),线程A将会进入阻塞状态,等线程B执行完毕后才会继续执行A线程

sleep() :让线程休眠

isAlive() :判断当前线程是否存活

package com.peng.demon01;

/*测试Thread类的方法
start():启动线程,并执行对象的run()方法
run() :线程在被调度时执行的操作
currentThread():静态方法,返回执行当前代码的线程
getName():获取当前线程的名字
setName():设置当前线程的名字
yield():释放CPU的执行权
join():如果在线程A中调用B线程的join(),线程A将会进入阻塞状态,等线程B执行完毕后才会继续执行A线程
*/

public class ThreadMethodTest {
    
    
    public static void main(String[] args) {
    
    
        Thread1 thread1 = new Thread1("金鱼姬");
        //thread1.setName("狂铁");//设置当前线程的名字
        thread1.start();
        //给主线程设置名字
        //    返回执行当前代码的线程
        Thread.currentThread().setName("主线程");
        for (int i = 0; i <100 ; i++) {
    
    
            if (i % 2==0){
    
    
                System.out.println(Thread.currentThread().getName()+"; "+i);
            }
            if (i==20)
            try {
    
    
                thread1.join();//当主线程执行到20时开始执行另一个线程
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }

        }
       //判断当前线程是否存活           false
        System.out.println(thread1.isAlive());
    }
}


class Thread1 extends Thread{
    
    
    @Override
    public void run() {
    
    
        for (int i = 0; i <100 ; i++) {
    
    
            if (i % 2==0){
    
    
               // try {
    
    
                   // sleep(1000);
               // } catch (InterruptedException e) {
    
    
                  //  e.printStackTrace();
               // }
                System.out.println(Thread.currentThread().getName()+"; "+i);
            }

            //if (i%20==0);
           // yield();//释放CPU的执行权
        }


    }
    //利用构造方法也可以给线程命名
       public  Thread1(String name){
    
    
        super(name);
       }


}

实现Runnable接口

  • 定义MyRunnable类实现Runnable接口
  • 实现run()方法,编写线程实行体
  • 创建线程对象,调用start()方法启动线程

推荐使用实现Runnable接口,可以避免单继承局限性,灵活方便,方便统一个对象被多个线程使用

package com.peng.demon01;

//创建线程方式2,:实现Runnable接口,重写run方法,执行线程需要丢入Runnable接口的实现类,调用start开启线程
public class TestThread03 implements Runnable{
    
    
    @Override
    public void run() {
    
    
        //线程体
        for (int i = 0; i <200; i++) {
    
    
            System.out.println("打王者荣耀"+i);
        }
    }
    public static void main(String[] args) {
    
    //main()线程,主线程

        //创建一个Runnable接口的实现类的对象
        TestThread03 testThread03 = new TestThread03();
        //创建线程对象,通过线程对象来开启线程
        // Thread new = new Thread(testThread03);
        //new Thread.start();
        new Thread(testThread03).start();

        for (int i = 0; i < 1000; i++) {
    
    
            System.out.println("不要打英雄联盟"+i);
        }
    }
}

并发问题

多个线程操作同一个资源的情况下,线程不安全,数据紊乱。

package com.peng.demon01;

//多个线程同时操作同一个对象    买火车票的例子
public class TestThread04 implements Runnable{
    
    
    //票数
    private int ticketNums = 10;
    @Override
    public void run() {
    
    
        while (true){
    
    //如果买到了票
            if (ticketNums<=0){
    
    
                break;//如果没票了就退出
            }                 //通过这个方法获得当前执行线程的名字
            System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNums--+"张票");
        }
    }
    public static void main(String[] args) {
    
    
        //创建Runnable实现类的对象
        TestThread04 ticket = new TestThread04();
        //开启多个线程
        new Thread(ticket,"狂铁").start();
        new Thread(ticket,"后羿").start();
        new Thread(ticket,"达摩").start();
    }
}

在这里插入图片描述

龟兔赛跑案例

package com.peng.demon01;
//模拟龟兔赛跑
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(1);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
            //判断比赛是否结束
            boolean flag = gameOver(i);
            if (flag==true){
    
    //如果比赛结束,就停止程序
                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();
    }

}

在这里插入图片描述

实现Callale接口

实现Callale接口的好处

  • 可以定义返回值
  • 可以抛出异常
package com.peng.demon02;

import com.peng.demon01.TestThread02;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

//线程创建方式三:实现Callable接口
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 testCallable01 = new TestCallable("http://www.xinhuanet.com/photo/2020-08/26/1126412315_15983723897731n.jpg",",新华网图片1.jpg");
        TestCallable testCallable02 = new TestCallable("http://www.xinhuanet.com/photo/2020-08/26/1126412315_15983723898911n.jpg",",新华网图片2.jpg");
        TestCallable testCallable03 = new TestCallable("http://www.xinhuanet.com/photo/2020-08/25/1126412104_15983627450851n.jpg",",新华网图片3.jpg");
        TestCallable testCallable04 = new TestCallable("http://www.xinhuanet.com/photo/2020-08/25/1126412104_15983627451171n.jpg",",新华网图片4.jpg");

        //启动线程
        //创建执行服务   ExecutorService,Executors是两个类    FixedThreadPool线程池
        ExecutorService ser = Executors.newFixedThreadPool(3);
        //提交执行 把三个线程提交上去,然后返回三个返回值,三个返回值都是true
        Future<Boolean> result1 = ser.submit(testCallable01);
        //submit方法:执行任务,有返回值,一般用来执行Callable接口
        Future<Boolean> result2 = ser.submit(testCallable02);
        Future<Boolean> result3 = ser.submit(testCallable03);

        //获取结果 获得返回值,返回值类型为boolean,返回值名字为r1,r2,r3
        boolean r1 = result1.get();
        boolean r2 = result1.get();
        boolean r3 = result1.get();

        System.out.println(r1);//true
        System.out.println(r2);//true
        System.out.println(r3);//true
        //关闭服务
        ser.shutdownNow();
    }
    //下载器
    class WebDownloader {
    
    
        //下载方法
        public void downloader(String url, String name) {
    
    
            try {
    
    //捕获异常
                // FileUtils是一个工具类,copyURLToFile是一个方法,方法的作用是把网络资源的地址变成文件
                FileUtils.copyURLToFile(new URL(url), new File(name));
            } catch (IOException e) {
    
    
                e.printStackTrace();
                System.out.println("IO异常,downloader方法出现问题");
            }
        }
    }
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/wpc2018/article/details/108269882