创建线程的三种方式,线程的方法,线程的优先级

面试题:进程和线程的区别?
进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位。
一个进程可以包含多个线程,而且至少包含一个线程。
地址空间:进程有自己独立的地址空间,每启动一个进程,系统都会为其分配地址空间,
线程没有独立的地址空间,同一进程的线程共享本进程的地址空间。
资源拥有:进程之间的资源是独立的,同一进程内的线程共享本进程的资源。
执行过程:每个独立的进程有一个程序运行的入口、程序执行序列和程序入口。
但是线程不能独立执行,必须依附在应用程序中,由应用程序提供多个线程执行控制。
面试题:怎么启动一个线程?调用run方法和start方法有什么区别?
调用start方法来启动线程。
run方法用来定义线程要执行的任务,如果直接调用run方法就是将其当作普通方法来调用,
程序会顺序执行,要等run方法的方法体执行完毕后才可以继续执行下面的代码;
start方法用来开启一个线程,会将该线程纳入到线程调度程序中,等待CPU分配时间片再运行,
运行时会自动调用run方法,但是无需等待run方法的方法体执行完毕也可以执行其他内容。

 

创建线程有几种方式,有什么区别呢?
创建线程有三种方式:
 1)继承Thread类创建线程
 2)实现Runnable接口创建线程
 3)使用Callable和Future创建线程
区别:
第二种和第三种的区别:
实现Runnable接口和实现Callable接口的方式基本相同,不过是实现Callable接口执行call()方法有返回值,实现Runnable接口线程执行体run()方法无返回值
第一种和第二种、第三种的区别:
1.继承Thread类后不能再继承其他类去复用方法
2.实现Runnable接口和实现Callable接口还可以实现其它接口或者继承其它的类
package thread;
/*
面试题:进程和线程的区别?
进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位。
一个进程可以包含多个线程,而且至少包含一个线程。
地址空间:进程有自己独立的地址空间,每启动一个进程,系统都会为其分配地址空间,
线程没有独立的地址空间,同一进程的线程共享本进程的地址空间。
资源拥有:进程之间的资源是独立的,同一进程内的线程共享本进程的资源。
执行过程:每个独立的进程有一个程序运行的入口、程序执行序列和程序入口。
但是线程不能独立执行,必须依附在应用程序中,由应用程序提供多个线程执行控制。
 */
/*
面试题:怎么启动一个线程?调用run方法和start方法有什么区别?
调用start方法来启动线程。
run方法用来定义线程要执行的任务,如果直接调用run方法就是将其当作普通方法来调用,
程序会顺序执行,要等run方法的方法体执行完毕后才可以继续执行下面的代码;
start方法用来开启一个线程,会将该线程纳入到线程调度程序中,等待CPU分配时间片再运行,
运行时会自动调用run方法,但是无需等待run方法的方法体执行完毕也可以执行其他内容。
 */

/**
 * 多线程
 * 线程:一个顺序的 单一的 程序执行流程就是一个线程。
 * 多线程:多个单一 顺序执行 的流程并发运行。
 *
 * 多个线程实际运行是走走停停的,线程调度程序会将CPU运行时间划分为若干时间片段
 * 并尽可能均匀的分配给每个线程,拿到时间片的线程会被CPU执行这段时间。
 * 当超时后,线程调度程序会再次分配一个时间片段给一个线程,使得CPU执行它。
 * 如此反复。由于CPU执行时间在纳秒级别,所以我们感觉不到切换线程运行的过程。
 * 所以微观上走走停停,宏观上感觉一起运行的现象称为并发运行。
 *
 * 创建线程的第一种方式:
 * 定义一个类继承自Thread,并重写run方法,在run方法中定义要与其他线程并发运行的任务。
 * 调用start方法启动线程。
 *
 * CPU是一个处理器 i5、i7、i9
 *
 * @author YanLy
 * @date 2021/6/1  11:30
 */
public class ThreadDemo1 {
    public static void main(String[] args) {
        // 1.实例化线程
        Thread t1 = new MyThread1();
        Thread t2 = new MyThread2();
        // 2.启动线程 -- 不能直接调用run方法!! -- 调用run方法是单纯的调方法 和线程无关
        // start方法调用后,线程纳入线程调度程序控制,run会自动执行。
        t1.start();
        t2.start();
    }
}
/*
第一种创建线程的方式优点在于结构简单,便于匿名内部类形式创建。
缺点:
1.直接继承线程,会导致不能再继承其他类去复用方法,这在实际开发中是非常不方便的。
2.定义线程的同时重写了run方法,会导致线程与线程任务绑定在一起,不利于线程的重用。
 */
class MyThread1 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("你瞅啥?");
        }
    }
}
class MyThread2 extends  Thread{
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("瞅你咋滴!");
        }
    }
}

 

package thread;

/**
 * 创建线程的第二种方式:
 * 实现Runnable接口单独定义线程任务
 *
 * @author YanLy
 * @date 2021/6/1  14:16
 */
public class ThreadDemo2 {
    public static void main(String[] args) {
        // 1.创建线程要执行的任务
        Runnable r1 = new MyRunnable1();
        Runnable r2 = new MyRunnable2();
        // 2.创建两个线程分别执行任务
        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);
        /*
        线程和任务分离开了,线程和任务的耦合度降低,更灵活
         */
        // 3.启动线程
        t1.start();
        t2.start();
    }
}
class MyRunnable1 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("早啊,海绵宝宝~");
        }
    }
}
class MyRunnable2 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("早上好!派大星~");
        }
    }
}

 

package thread;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * 第三种创建线程的方式
 * 实现Callable接口定义要执行的任务
 * 需要重写call方法,call方法有返回值,也可以抛出异常。
 *
 * Callable接口的实例不能直接作为Thread实例的参数,需要搭配Future接口一块使用,
 * FutureTask是Future的实现类,可以对Runnable或者Callable的任务执行取消、
 * 查询、获取结果等操作。
 *
 * Callable接口和Future接口是JDK5以后开始提供的。
 *
 * @author YanLy
 * @date 2021/6/1  14:35
 */
public class ThreadDemo3 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable c1 = new MyCallable1();
        Callable c2 = new MyCallable2();

        FutureTask f1 = new FutureTask(c1);
        FutureTask f2 = new FutureTask(c2);

        Thread t1 = new Thread(f1);
        Thread t2 = new Thread(f2);

        t1.start();
        t2.start();

        //获取call方法的返回值
        String s1 = (String) f1.get();
        String s2 = (String) f2.get();
        System.out.println(s1);
        System.out.println(s2);

    }
}
class MyCallable1 implements Callable{
    @Override
    public Object call() throws Exception {
        for (int i = 0; i <1000; i++) {
            System.out.println("今天你学废了吗?");
        }
        return "MyCallable1";
    }
}
class MyCallable2 implements Callable{
    @Override
    public Object call() throws Exception {
        for (int i = 0; i <1000; i++) {
            System.out.println("学不会啦");
        }
        return "MyCallable2";
    }
}

 

package thread;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

/**
 * 使用匿名内部类完成线程的创建
 *
 * @author YanLy
 * @date 2021/6/1  15:19
 */
public class ThreadDemo4 {
    public static void main(String[] args) {
        // 第一种创建线程的方法
        Thread t = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    System.out.println("Thread");
                }
            }
        };
        t.start();
        // 第二种创建线程的方法
        Runnable r = new Runnable(){
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    System.out.println("Runnable");
                }
            }
        };
        // lambda表达式
        Runnable r2 = ()->{
            for (int i = 0; i < 1000; i++) {
                System.out.println("Runnable-lambda");
            }
        };
        // 如果只有一句代码可以省略大括号
        Runnable r3 = ()-> System.out.println("Runnable-lambda-only");

        // 第三种创建线程的方法
        Callable c = new Callable(){
            @Override
            public Object call() throws Exception {
                for (int i = 0; i < 1000; i++) {
                    System.out.println("Callable");
                }
                return null;
            }
        };
        FutureTask f = new FutureTask(c);
        Thread t1 = new Thread(f);
        // lambda表达式
        Callable c1 = ()->{
            for (int i = 0; i < 1000; i++) {
                System.out.println("Callable");
            }
            return null;
        };
        // 如果只有一句代码可以省略大括号
        Callable c2 = ()->null;



    }
}
package thread;

import java.util.Scanner;

/**
 * 线程提供了一个静态方法:
 * static void sleep(long ms)
 * 使调用该方法的线程进入阻塞状态指定毫秒。超时后线程会自动回到RUNNABLE状态,
 * 等待再次获取时间片并发运行。
 *
 * @author YanLy
 * @date 2021/6/1  15:46
 */
public class SleepDemo {
    // InterruptedException 被中断异常
    public static void main(String[] args){
        /*
        实现倒计时程序:
        程序启动后要求用户输入一个数字,然后从这个数字开始每秒递减,
        到0时输出"时间到",程序结束
         */
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入一个数字");
        int num = scanner.nextInt();
        while(num>0){
            System.out.println(num--);
            /*
            sleep方法要求我们必须处理中断异常:InterruptedException
            当一个线程调用sleep方法处于阻塞的过程中,该线程的Interrupt方法
            被调用时会中断它的sleep阻塞,并抛出上述异常。
             */
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("时间到!");
    }
}
package thread;
// InterruptedException 中断异常
/**
 * sleep方法要求我们必须处理中断异常:InterruptedException
 * 当一个线程调用sleep方法处于阻塞的过程中,该线程的Interrupt方法
 * 被调用时会中断它的sleep阻塞,并抛出上述异常。
 *
 * @author YanLy
 * @date 2021/6/1  16:14
 */
public class SleepDemo2 {
    public static void main(String[] args) {
        Thread lin = new Thread(){
            @Override
            public void run() {
                System.out.println("林:正在打扫...");
                try {
                    Thread.sleep(100000000);
                } catch (InterruptedException e) {
                    System.out.println("林:干嘛呢!干嘛呢!");
                }
            }
        };
        Thread huang = new Thread(){
            @Override
            public void run() {
                System.out.println("开始砸墙!");
                for (int i = 0; i < 5; i++) {
                    System.out.println("黄:80!");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("哐当!!!");
                System.out.println("黄:搞定!");
                lin.interrupt();// 中断lin线程的睡眠阻塞
            }
        };
        lin.start();
        huang.start();

    }
}
package thread;

/**
 * 线程提供了一个方法:
 * void join()
 * 该方法允许调用这个方法的线程在该方法所属线程上等待(阻塞),直到该方法所属线程结束后才会解除等待,
 * 继续后续的工作,所以join方法可以用来协调线程的同步运行。
 *
 * 同步:多个线程执行过程存在先后顺序进行
 * 异步:多个线程各干各的  -- 线程本身就是异步运行的
 *
 * @author YanLy
 * @date 2021/6/1  16:31
 */
public class JoinDemo {

    // 标识图片是否下载完毕
    static boolean isFinish = false;

    public static void main(String[] args) {
        /*
        当一个方法的局部内部类中引用了这个方法的其他局部变量时,
        这个变量必须是final的,这是由于JVM内存分配问题导致的,当成语法要求去遵守即可。
        因此被局部内部类引用的局部变量是不能被二次赋值的。
         */
//        boolean isFinish = false;
        Thread download = new Thread(){
            @Override
            public void run() {
                System.out.println("download:开始下载图片...");
                for (int i = 0; i < 100; i++) {
                    System.out.println("download:"+i+"%");
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("download:图片下载完毕!");
                isFinish = true;
            }
        };
        Thread show = new Thread(){
            @Override
            public void run() {
                System.out.println("show:正在显示图片...");
                try {
                    // show开始阻塞,知道download执行完毕再继续后续的操作
                    // 保证download先运行
                    download.join(); // join加入 把时间片分配给download 等download加载完再执行自己的
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (!isFinish){
                    // 当一个线程的run方法抛出一个异常,则线程会结束
                    throw new RuntimeException("show:图片显示失败!");
                }
                System.out.println("show:图片显示成功");
            }
        };

        download.start();
        show.start();
    }
}
package thread;

/**
 * java中所有的代码都是靠线程运行的,main方法也不例外。
 * java程序开始运行时,JVM会创建一条线程来执行main方法,
 * 这条运行main方法的线程的名字叫做"main",也称为主线程
 *
 * 线程提供了一个静态方法,可以获取到运行该方法的线程
 * static Thread currentThread()  -- 获取到当前的线程  current 当前的
 *
 * @author YanLy
 * @date 2021/6/1  17:16
 */
public class CurrentThreadDemo {
    public static void main(String[] args) {
        // 获取到运行main方法的线程
        Thread main = Thread.currentThread();
        System.out.println("运行main方法的线程是:" + main);
        // Thread[main,5,main]  -- [线程名称,线程优先级,线程所属线程组]
        // 5 -- 优先级 -- 默认都是 5



        // 在主线程上再创建一条线程,让它并发运行
        Thread t = new Thread(){
            @Override
            public void run() {
                // 获取运行当前run方法的线程
                Thread t = Thread.currentThread();
                System.out.println("运行run方法的线程是:"+t);
                // Thread[Thread-0,5,main] -- [线程名称,线程优先级,线程所属线程组]

                doSome(); // 让t线程调用doSome方法
                // Thread[Thread-0,5,main]  -- [线程名称,线程优先级,线程所属线程组]
            }
        };
        t.start(); // 当t线程调用start方法以后,就与主线程并发了。

        doSome();// 让主线程执行doSome方法
        // main方法的线程和我们自己建的线程是并发运行,不一定会先运行谁。所以与放置位置无关
    }
    public static void doSome(){
        Thread t = Thread.currentThread();
        System.out.println("运行doSome方法的线程是:" + t);
    }
}
package thread;

/**
 * 线程的优先级
 * 线程有10个优先级,使用整数1-10表示
 * 1为最低优先级,10为最高优先级,5为默认值。
 *
 * 线程start方法后会纳入线程调度器中统一管理,线程只能被动的被分配时间片并发运行,
 * 而无法主动索取时间片,线程调度器会尽可能均匀的将时间片分配给每个线程。
 * 调整线程的优先级可以最大程度的干涉获取时间片的几率,
 * 优先级越高的线程获取时间片的次数越多,反之则越少(前提是这些线程在同一个CPU核心上)。
 *
 * CPU在版本之上分几核
 * 由于现在的电脑都是多核的电脑,所以设置优先级效果并不明显,只是尽量。
 *
 * @author YanLy
 * @date 2021/6/1  17:37
 */
public class PriorityDemo {
    public static void main(String[] args) {
        Thread min = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    System.out.println("min");
                }
            }
        };
        Thread normal = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    System.out.println("normal");
                }
            }
        };
        Thread max = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    System.out.println("max");
                }
            }
        };
        // 设置线程优先级
        min.setPriority(Thread.MIN_PRIORITY);//最小
        max.setPriority(Thread.MAX_PRIORITY);//最大
        // 开启线程
        min.start();
        normal.start();
        max.start();
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值