其他分享
首页 > 其他分享> > 线程(1)

线程(1)

作者:互联网

"一步一步"

目录

1、什么是线程 ?那进程 ??

进程和线程本质区别在于每个进程拥有自己的一整套变量,线程共享数据

2、如何创建一个线程以及使用

2.1 创建方式一:继承Thread(不常用)

1、创建一个Thread 的子类

2、重写Thread 类的 run() 方法 ——> 需要做的事

3、创建Thread 类的子类的对象

4、通过此对象调用 start() 方法

// 创建线程
public class MyThread extends Thread {
    // 1、创建Thread 的一个子类

    // 2、重写Thread 类的run()方法
    public void run() {
        // 要做什么
        for (int i = 0; i < 20 ; i++) {
            if (i % 2 ==0){
                System.out.println(i);
            }
        }
    }
    // 测试
    // 3、创建子类对象
	MyThread myThread = new MyThread();
    // 4、调用start()方法
    myThread.start();   
    /*一个主线程,一个MyThread线程*/

通过调试发现,我们执行到myThread.start() 时,它自动跳转执行了MyThread中的run() 方法,

1、启动当前线程

2、调用当前线程的run() 方法

note:

如果我们直接通过当前对象调用run() 方法myThread.run();,此时只是在同一线程下的普通方法调用,实则就不是在开启新线程了。

不可以让已经start() 方法的线程再start()------> 报IllegalThreadStateException,那如何再使用线程呢?——> 新建线程对象再调用即可

总结:要想创建多个线程,就去new 多个对象

​ 启动线程只能通过start()

2.2 方式二 :实现Runnable接口

1、创建一个实现Runnable 接口的实现类;

2、实现类里实现Runnable接口的抽象方法run(); (implements)

3、创建实现类对象;

4、将此对象作为参数传入Thread类的构造器中,创建Thread类的对象

5、通过Thread的对象调用start();——> 调用的是Runnable类型的target的run().

note:

// start() 方法是调用当前线程的 run() 方法,此时我们通过创建 Thread 类的对象,而用这个对象是怎么执行实现类里的 run() 呢 ??

看源码:

public void run() {
    if (target != null) {
        target.run();
    }
}
// 进入target发现还是在Thread类 中声明了一个属性:
private Runnable target;
// 我们刚才new出来的构造器,调用Thread类里的run()时,target已经不为空了,所以调的是target的run();
public Thread(Runnable target){    
}

看例子:

//构造线程函数
public class Test02 implements Runnable{    //1、实现接口
    //实现函数功能在类里
       //2、通过传参手动实现线程定义
    
    private String name;//定义线程名称---全局变量name

    public Test02(String name){       //构造函数-----局部变量参数name
        this.name=name;
        }
        private String getName(){
        	return this.name;//返回当前线程名称的功能
        }
    //3覆写
   //需执行代码-----自定义线程必须要有run函数用于执行线程要执行的代码
    public void run(){
        System.out.println("我是"+this.getName()+"线程");
            for (int i = 0; i <=100 ; i++) {
                System.out.println(this.getName()+"跑了"+i+"米");
                /* 注意,这里有getName()方法是因为前面定义了这个功能,
                如果没有就可用Thread.currentThread().getName() */
               
                try{
                Thread.sleep((long)Math.random()*1000);//休眠---计时等待
                }catch(InterruptedException exp){
                    System.out.println(this.getName()+"发生异常!");
                }
            }
    }

    public static void main(String[] args) {
        //两个子线程创建及启动
        //构造实现类对象---并行运行
        Test02 WG_runable=new Test02("乌龟");
        //WG_runable必须依赖于Thread才可构建线程对象

        Test02 TZ_runable=new Test02("兔子");

       Thread WG=new Thread(WG_runable); //2、通过传参(target)手动实现线程定义
       Thread TZ=new Thread(TZ_runable);

       WG.start();
       TZ.start();
    }
}

例2:

public class NightRunnable implements Runnable {
    public void run(){
        for (int i = 0; i < 10; i++) {
            System.out.println("线程1正在执行"+new Date().getTime());
        }
    }

    public static void main(String[] args) {

        Thread thread=new Thread(new NightRunnable());//接口里无方法,只能手动传参
        thread.start();//start是Thread的方法
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"正在执行"+new Date().getTime());
        }
    }
}

2.2.1 关于线程的两种创建方式

2.3 方式三:实现Callable接口

与方式二相比:

run()方法可以有返回值;

方法可以抛出异常;

支持泛型的返回值;

需要借助FutureTask类,比如获取返回结果;

1、创建一个实现Callable接口的实现类;

2、实现call(),call()里面声明的是需要执行的操作;

3、创建Callable接口实现类的对象;(A)

4、创建以Callable接口实现类的对象作为参数的FutureTask对象;

5、将FutureTask对象作为参数,传递到Thread类的构造器中,创建Thread类对象调用start()。

new Thread(new FutureTask(A)).start();

// 6、获取Callable实现类重写的call()的返回值。

public class CallableThread implements Callable {//接口定义了n种方法,class 就要定义n种方法
    @Override
    public String call()throws Exception/*函数定义,必须写*/{
        System.out.println("我是" + Thread.currentThread().getName() + "线程");
        //我是Thread-0线程(此名称为系统赋予)
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "跑了" + i + "米");
            try {
                //                MyThread1.sleep(1000);//每跑一米睡一秒
                Thread.sleep((long) Math.random() * 10000);//随机休息,验证两个线程互不干扰
                throw new IOException(Thread.currentThread().getName() +"累了");
                /*throw new IOException();*/
            } catch (InterruptedException exp) {
                System.out.println(Thread.currentThread().getName() + "发生异常");
            }
        }
        return Thread.currentThread().getName()+"到达终点";/*函数定义,必须写*/
    }

}
public class NightCallable implements Callable<String> {

   public String call()throws Exception{
       //@return computed result
       //     * @throws Exception if unable to compute a result

        for (int i = 0; i <10 ; i++) {
            System.out.println(Thread.currentThread().getName()+"正在执行"+new Date().getTime());
        }
        return "执行完毕";
    }

    public static void main(String[] args) throws ExecutionException ,InterruptedException{
        FutureTask task=new FutureTask(new NightCallable());
        Thread thread=new Thread(task);
        thread.start();
        for (int i = 0; i <10 ; i++) {
            System.out.println(Thread.currentThread().getName()+"线程正在执行");
        }
        System.out.println(task.get());// 这是个对象,目的就只是为了获取call()的返回值//get异常
         // get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值
    }
}

关于Future接口:

可以对具体Runnable、Callable任务的执行结果进行取消、查询是否完成、获取结果等;

FutureTask是Future接口的唯一实现类;

FutureTask同时实现了Runnable、Future接口,它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。

如何理解实现Callable接口比实现Runnable创建多线程要强大 ??

1、call() 可以有返回值;(分线程执行完可以给另外的线程返回一个结果)

2、call() 可以抛出异常,被外面的操作捕获,获取异常信息;

3、Callable支持泛型;
image

2.4 方式四:线程池

经常创建和销毁、使用量特别大的资源,比如并发情况下的线程对性能影响很大

3、线程的生命周期

4、sleep()

5、join()

插队

标签:Runnable,run,Thread,创建,线程,public
来源: https://www.cnblogs.com/fulfill/p/16543389.html