java多线程学习一、线程介绍、线程创建的3种方式、lambda创建方式、线程状态、线程示例:12306买票和银行取钱

前言

之前在学校学习线程,就是很简单的学习创建和使用,一般也没用过线程,因为在学校根本用不到并发。线程的好处有很多:提高资源利用率,让电脑的资源充分利用起来;可以提高程序的运行速度;等等。
在公司,一般都会用到线程开发,juc的高并发开发、线程池的使用。一般这线都是在学校用不到也学不到的,所以我之前也没有搞过、学习过。所以我现在用到了,我就写个博客,记录一下,学习一下。
我想记录的东西有很多,也不知道能写多少,我尽力哈。

  • 线程基础
  • 线程状态
  • 线程同步
  • JUC高并发
  • 线程池

一、线程简介

1.概述

  • 线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
  • 在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。
  • 线程是独立调度分派的基本单位。

简单一点解释

  • 方法间调用:普通方法调用,从哪里来到哪里去,闭合的一条路径。
  • 多线程使用:开辟了多条路径。
    在这里插入图片描述

2.进程、线程 区别

在这里插入图片描述

区别进程线程
根本区别作为资源分配的单位调度和执行的单位
开销每隔进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销。线程可以看成轻量级的进程,同一类线程共享赛马和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换的开销小。
所处环境再操作系统中能同时运行多个任务(程序)再同一应用中有多个顺序流同时执行
分配内存系统再运行的时候会为每个进程分配不同的内存区域除了CPU之外,不会为线程分配内存(线程所使用的资源是它所属的进程的资源),线程组只能共享资源
包含关系没有线程的进程是可以被看作单线程的,如果一个进程内拥有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的。线程是进程的一部分,所以线程有的时候被称为是清权进程或者轻量级进程

注意:很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核,如服务器。如果是 模拟出来的多线程,即一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,因为 切换的很快,所以就有同时执行的错觉。

3. 核心概念

• 线程就是独立的执行路径;
• 在程序运行时,即使没有自己创建线程,后台也会存在多个线程, 如gc线程、主线程;
• main()称之为主线程,为系统的入口点,用于执行整个程序;
• 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排 调度,调度器是与操作系统紧密相关的,先后顺序是不能人为的 干预的;
• 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控 制;
• 线程会带来额外的开销,如cpu调度时间,并发控制开销
• 每个线程在自己的工作内存交互,加载和存储主内存控制不当会 造成数据不一致。

二、 线程创建

1.概述

线程创建有三种方式,如图所示:第三种实现Callable方式 是juc高级编程里的方式,目前只知道就可以啦。
在这里插入图片描述

2. 第一种方式继承Thread

在这里插入图片描述

1) 继承Thread

package com.feng.ch01_thread;
/**
 * 创建线程方式一:
 *  1. 创建:继承Thread + 重写run
 *  2. 启动: 创建子类对象 + start方法
 */
public class StartThread extends Thread {

    @Override
    public void run() {
        for (int i = 0 ; i<20; i++){
            System.out.println("一边唱歌");
        }
    }

    public static void main(String[] args) {
        // 创建子类对象
        StartThread startThread = new StartThread();
        // 启动
        startThread.start(); // 不保证立即运行, CPU 调用
//        startThread.run(); // 普通方法调用
        for (int i = 0; i< 20 ; i++){
            System.out.println("一遍coding");
        }
    }
}

2) 示例:下载图片

package com.feng.ch02_webdownload;

public class ThreadDownload extends Thread {

    private String  url; //远程路径
    private String name; // 存储名字

    public ThreadDownload(String url, String name){
        this.url = url;
        this.name = name;
    }

    @Override
    public void run() {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.download(url, name);
        System.out.println(name);
    }

    public static void main(String[] args) {
        ThreadDownload td01 = new ThreadDownload("http://article-fd.zol-img.com.cn/t_s500x2000/g1/M01/01/0F/ChMljV2C4SuIZfJoAABdiz-TYC8AAP2EQDL4VIAAF2j137.jpg", "phone.jpg");
        ThreadDownload td02 = new ThreadDownload("http://tblg.k-img.com/restaurant/images/Rvw/12277/12277487.jpg", "spl.jpg");
        ThreadDownload td03 = new ThreadDownload("http://thumbs.dreamstime.com/b/key-success-to-18466568.jpg", "success.jpg");

        td01.start();
        td02.start();
        td03.start();
    }
}

3. 第二种方式:实现Runnable

  1. 创建目标对象: IDownloader id =new IDownloader(“图片地址”,“baidu.png”);
  2. 创建线程对象+关联目标对象: Thread t =new Thread(id);
  3. 启动线程: t.start()
package com.feng.ch01_thread;
/**
 * 创建线程方式二:
 *  1. 创建:实现implement + 重写run
 *  2. 启动: 创建实现类对象 + Thread对象 + start方法
 *
 *  推荐:避免单继承的局限性,优先使用接口
 *  方面共享资源
 */
public class StartRunnable implements Runnable {

    @Override
    public void run() {
        for (int i = 0 ; i<20; i++){
            System.out.println("一边唱歌");
        }
    }
    public static void main(String[] args) {
        /*
        // 创建实现类对象
        StartRunnable startThread = new StartRunnable();
        // 创建代理类对象
        Thread ch01_thread = new Thread(startThread);
        //启动
        ch01_thread.start();
        */
// 链式写法
        new Thread(new StartThread()).start();
        for (int i = 0; i< 20 ; i++){
            System.out.println("一遍coding");
        }
    }
}

5. 第三种方式:实现Callable

  1. 创建目标对象: StartCallableDownload_simple cd =new StartCallableDownload_simple ();
  2. 创建执行服务: ExecutorService ser=Executors.newFixedThreadPool(3); // 3个线程
  3. 提交执行: Future result1 =ser.submit(cd1) ;
  4. 获取结果: boolean r1 =result1.get();
  5. 关闭服务: ser.shutdownNow();
package com.feng.ch04_callable;
import java.util.concurrent.*;
public class StartCallableDownload_simple implements Callable<Integer> {

    @Override
    public Integer call() {
        System.out.println("name:"+Thread.currentThread().getName());
        return 0;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
// 1、 创建目标对象
        StartCallableDownload_simple scd01 = new StartCallableDownload_simple();
        StartCallableDownload_simple scd02 = new StartCallableDownload_simple();
        StartCallableDownload_simple scd03 = new StartCallableDownload_simple();

        // 高级的juc 编程(java.util.concurrent),

        // 2、创建执行服务
        ExecutorService executorService = Executors.newFixedThreadPool(6);  // 6个线程
        // 3、提交执行
        Future<Integer> result01 = executorService.submit(scd01);
        Future<Integer> result02 = executorService.submit(scd02);
        Future<Integer> result03 = executorService.submit(scd03);
        // 4、获取结果   这里需要抛出 两个 异常
        Integer aBoolean = result01.get();
        Integer aBoolean1 = result02.get();
        Integer aBoolean2 = result03.get();
        System.out.println(aBoolean2);
        // 5、关闭服务
        executorService.shutdown();
    }
}

在这里插入图片描述

5. Thread对比Runnable

在这里插入图片描述

6. 线程示例

1) 龟兔赛跑

package com.feng.ch01_thread;

/**
 * 模拟龟兔赛跑
 */
public class RacerRunnable implements Runnable {
    public static void main(String[] args) {
        RacerRunnable racerRunnable = new RacerRunnable();
        new Thread(racerRunnable, "tortoise").start();
        new Thread(racerRunnable, "rabbit").start();
    }
    private String winner;// 胜利者
    @Override
    public void run() {
        for (int step = 1; step <= 100; step++){
            // 模拟兔子休息
            if (Thread.currentThread().getName().equals("rabbit") && (step%10==0)){
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()+"-->"+step);
            // 比赛是否结束
            boolean b = gameOver(step);
            if (b){
                break;
            }
        }
    }
    public boolean gameOver(int step){
        if (winner!=null){
            return true;
        }else{
            if (step == 100){
                winner = Thread.currentThread().getName();
                System.out.println("winner==>"+ winner);
                return true;
            }
        }
        return false;
    }
}

在这里插入图片描述

2) 12306购票

package com.feng.ch03_bugticket03;

/**
 * 共享资源, 并发(线程安全)
 */
public class Web12306 implements Runnable {

    // 票数
    private int ticketNums = 99;

    @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) {
        // 一份资源
        Web12306 web12306 = new Web12306();
        System.out.println(Thread.currentThread().getName());
        // 多份代理
        new Thread(web12306, "码畜").start();
        new Thread(web12306, "码农").start();
        new Thread(web12306, "码蟥").start();
    }
}

在这里插入图片描述
出现了负数和重复数据,则出现了 共享资源、线程安全 的问题。

三、静态代理和动态代理

概念:使用一个代理对象将对象包装起来,然后用该代理对象来取代该对象,任何对原始对象的调用都要通过代理,代理对象决定是否以及何时调用原始对象的方法

1. 静态代理

1) 概述

要求被代理类和代理类同时实现相应的一套接口,通过代理类调用重写接口的方法,实际上调用的是原始对象的同样的方法
在这里插入图片描述
Cilent调用Source的method()方法,实际上是Proxy来调用method()方法,静态代理中Source跟Proxy都要实现接口Sourceable。

2) 示例

首先是父接口 Animal.java

package com.feng.springboottest.other.staticproxy;

public interface Animal {
    public void action();
    public void breath();

}

Cat.java

package com.feng.springboottest.other.staticproxy;

// 被代理的类
public class Cat implements Animal {
    @Override
    public void action() {
        System.out.println("喵喵喵~~~~~~~");
    }

    @Override
    public void breath() {
        System.out.println("喵式呼吸法~~~~~~~");
    }
}

CatProxy.java

package com.feng.springboottest.other.staticproxy;

// 代理类
public class CatProxy implements Animal {

    //真正要代理的类
    Cat cat;

    public CatProxy(Cat cat) {
        this.cat = cat;
    }

    @Override
    public void action() {
        System.out.println("==========catProxy 代理类执行开始!=============");
        //实质上在代理类中是调用了被代理实现接口的方法
        cat.action();
        System.out.println("==========catProxy 代理类执行结束!===========");
    }

    @Override
    public void breath() {
        System.out.println("==========catProxy 代理类执行开始!=============");
        cat.breath();
        System.out.println("==========catProxy 代理类执行结束!===========");
    }
}

TestCatStaticProxy.java

package com.feng.springboottest.other.staticproxy;

public class TestCatStaticProxy {
    public static void main(String[] args) {
        //被代理的类Cat,Cat实现了Animal接口
        Cat cat = new Cat();
        //代理类CatProxy,也实现了Animal接口
        CatProxy catProxy = new CatProxy(cat);
        //代理类来调用方法,实际上调用的是Cat的action(),breath()方法
        catProxy.action();
        catProxy.breath();
    }

}

运行结果:
在这里插入图片描述
从运行结果可以看到其实执行的是被代理类的对象.
从这里我们会想,如果我想再创建一个Dog对象,又需要重新为Dog创建一个代理对象,如下:

public class Dog implements Animal {
    @Override
    public void action() {
        System.out.println("汪汪汪~~~~~~~");
    }

    @Override
    public void breath() {
        System.out.println("狗式呼吸法~~~~~~~");
    }
}
package com.feng.springboottest.other.staticproxy;

public class DogProxy implements Animal {
    Dog dog;

    public DogProxy(Dog dog) {
        this.dog = dog;
    }

    @Override
    public void action() {
        System.out.println("==========dogProxy 代理类执行开始!=============");
        //实质上在代理类中是调用了被代理实现接口的方法
        dog.action();
        System.out.println("==========dogProxy 代理类执行结束!===========");
    }

    @Override
    public void breath() {
        System.out.println("==========dogProxy 代理类执行开始!=============");
        //实质上在代理类中是调用了被代理实现接口的方法
        dog.action();
        System.out.println("==========dogProxy 代理类执行结束!===========");
    }
}
package com.feng.springboottest.other.staticproxy;

public class TestDogStaticProxy {
    public static void main(String[] args) {
        Dog dog = new Dog();
        DogProxy dogProxy = new DogProxy(dog);
        dogProxy.action();
        dogProxy.breath();
    }

    /**
     * 每次我要新加入一个实现Animal接口的对象的话,都要重新创建一个代理对象,这样会非常的麻烦,
     * 这其实是静态代理的缺点,动态代理
     */

}

在这里插入图片描述
每次我要新加入一个实现Animal接口的对象的话,都要重新创建一个代理对象,这样会非常的麻烦,
这其实是静态代理的缺点,
接下来就看 动态代理吧

2. 动态代理

1) 概述

动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象,下面直接看代码:

2) 示例

还是Animal.java

package com.feng.springboottest.other.staticproxy.dynamicproxy;

public interface Animal {

    public void action();
    public void breath();
}

Cat

package com.feng.springboottest.other.staticproxy.dynamicproxy;

// 被代理类
public class Cat implements Animal {
    @Override
    public void action() {
        System.out.println("喵喵喵~~~~");

    }
    @Override
    public void breath() {
        System.out.println("猫式呼吸法~~~~");
    }
}

Dog.java

package com.feng.springboottest.other.staticproxy.dynamicproxy;

public class Dog implements Animal {
    @Override
    public void action() {
        System.out.println("汪汪汪~~~~~");
    }
    @Override
    public void breath() {
        System.out.println("狗式呼吸法~~~~");
    }
}

MyProxy.java

package com.feng.springboottest.other.staticproxy.dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyProxy implements InvocationHandler {

    Object obj;

    public MyProxy() {
    }

    public MyProxy(Object obj) {
        this.obj = obj;
    }

    /**
     *代理类调用方法时,都会调用invoke方法
     * @param proxy
     * @param method  代理对象执行的方法
     * @param args   参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("==============代理类开始执行!!!!=============");
        //returnVal是方法的返回值
        Object returnVal = method.invoke(obj, args);
        System.out.println("==============代理类执行结束!!!!=============");
        return returnVal;
    }
}

ProxyUtil.java

package com.feng.springboottest.other.staticproxy.dynamicproxy;

import java.lang.reflect.Proxy;

public class ProxyUtil {
    public static Object getProxyInstance(Object obj){
        MyProxy proxy = new MyProxy(obj);
        /*
         *  obj.getClass().getClassLoader():被代理对象的类加载器
         *  obj.getClass().getInterfaces() :被代理对象 实现 的接口 (因为只有一个接口)
         *  proxy : 实现InvocationHandler的接口
         *
         *  实质上是通过反射将 被代理类的加载器 和接口 与代理对象 关联起来
         *  obj :是被代理的对象
         */
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), proxy);
    }
}

TestDynamicProxy.java

package com.feng.springboottest.other.staticproxy.dynamicproxy;

import com.feng.springboottest.other.staticproxy.Cat;

public class TestDynamicProxy {
    public static void main(String[] args) {
        Cat cat = new Cat();
		// 获取 代理类的 实例(通过反射)
        Object proxyInstance = ProxyUtil.getProxyInstance(cat);
        Animal animal = (Animal) proxyInstance;
        animal.action();
        animal.breath();

        Dog dog = new Dog();
        Object proxyInstance1 = ProxyUtil.getProxyInstance(dog);
        Animal animal1 = (Animal) proxyInstance1;
        animal1.action();
        animal1.breath();
    }
}

动态代理的代理对象是 在运行时动态创建目标类的代理对象,而静态代理是需要为每个目标类创建代理对象,动态代理只需要一个方法就可以,相比静态代理代码冗余量减少了。

四、 lambda表达式创建进程

从普通的thread实现 到jdk8的实现的转化,
从静态内部类-》局部内部类-》匿名内部类-》lambda表达式

package com.feng.ch06_lambdaThread;

public class LambdaThread {

    // 第一次简化:静态内部类
    static class Test01 implements Runnable{
        @Override
        public void run() {
            System.out.println("一边听歌");
        }
    }

    public static void main(String[] args) {
        new Thread(new Test01()).start();

        //第二次简化:局部内部类
        class Test02 implements Runnable{
            @Override
            public void run() {
                System.out.println("一边看书");
            }
        }
        new Thread(new Test02()).start();

        // 第三次简化: 匿名内部类, 必须借助接口或者父类
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("一边coding");
            }
        }).start();

        // 第四次简化: jdk8 简化  lambda表达式
        new Thread(()->{
            System.out.println("一边学习");
        }).start();
    }
}

五、 线程状态

1. 概述

  1. 新生状态:一旦 Thread thread = new Thread();线程对象就进入了新生状态。
  2. 就绪状态:进入其状态的四个情况
    thread.start();
    解除阻塞中方法;
    thread.yield方法; 高风亮节,让出线程,让本线程进入就绪状态
    jvm切换,jvm将cpu从本地线程切换到其他线程。
  3. 运行状态:一定会从就绪状态被CPU调度到了,才会进行运行
  4. 堵塞状态:其发生的四个情况
    Thread.sleep();占着资源休眠。
    thread.wait(); 不占资源,站在一边等待。
    thread.join; 加入、合并、插队,等别人用完资源,在用。
    read 、write; 通过操作系统调用
  5. 死亡状态:
    stop(); 不推荐使用,不安全。过时。
    destroy();不推荐使用,不安全。过时。
    一般是让代码执行完,或者想方设法让代码执行完。设置标志。
    在这里插入图片描述
    在这里插入图片描述

2. 线程方法

  1. sleep ()
    • 使线程停止运行一段时间,将处于阻塞状态
    • 如果调用了sleep方法之后,没有其他等待执行的线程,这个时候当前线程不会马上恢复执行!
  2. join ()
    • 阻塞指定线程等到另一个线程完成以后再继续执行。 合并线程,也指插入线程。
  3. yield ()
    • 让当前正在执行线程暂停,不是阻塞线程,而是将线程转入就绪状态;
    • 调用了yield方法之后,如果没有其他等待执行的线程,此时当前线程就会马上恢复执行!
  4. setDaemon()
    • 可以将指定的线程设置成后台线程,守护线程;
    • 创建用户线程的线程结束时,后台线程也随之消亡;
    • 只能在线程启动之前把它设为后台线程
  5. setPriority(int newPriority) getPriority()
    • 线程的优先级代表的是概率
    • 范围从1到10,默认为5
  6. stop()停止线程
    • 不推荐使用

1) 线程停止

  • 不使用JDK提供的stop()/destroy()方法(它们本身也被JDK废弃了)。
  • 提供一个boolean型的终止变量,当这个变量置为false,则终止线程的运行。
package com.feng.state;

/**
 * 终止线程
 * 1、线程正常执行完毕-->次数
 * 2、外部干涉 -->加入标识
 * 不要使用stop destroy
 *
 */
public class ch01_TerminateThread implements Runnable {
    //1、加入标识 标记线程体是否可以运行
    private boolean flag = true;
    private String name;

    public ch01_TerminateThread(String name) {
        this.name = name;
    }
    //3、对外提供方法改变标识
    public void terminate() {
        this.flag = false;
    }
    @Override
    public void run() {
        int i=0;
        //2、关联标识,true-->运行 false -->停止
        while(flag) {
            System.out.println(name+"-->"+i++);
        }
    }
    public static void main(String[] args) {
        ch01_TerminateThread tt = new ch01_TerminateThread("C罗");
        new Thread(tt).start();
        for(int i=0;i<=99;i++) {
            if(i==88) {
                tt.terminate();//线程的终止
                System.out.println("tt game over");
            }
            System.out.println("main-->"+i);
        }
    }
}

2) Sleep()

拿住当前对象或者资源,进行占用而不使用,让 本身进程 和 其他消费该对象或者资源的进程 进入堵塞状态。这个特点是针对wait()方法而言。
这是一个静态方法,使用:Thread.sleep()。因为是 Thread,所以是当前的进程进行堵塞。
一般使用sleep()方法 进行模拟网络延时,在模拟网络延时的时候,放大了出现问题的概率。
• sleep(时间)指定当前线程阻塞的毫秒数;
• sleep存在异常InterruptedException;
• sleep时间达到后线程进入就绪状态;
• sleep可以模拟网络延时、倒计时等。
• 每一个对象都有一个锁,sleep不会释放锁;

a) 示例1 模拟12306 抢票
package com.feng.state;
/**
 * sleep模拟网络延时,放大了发生问题的可能性
 *
 */
public class ch02_BlockedSleep01 {

    public static void main(String[] args) {
        //一份资源
        Web12306 web =new Web12306();
        System.out.println(Thread.currentThread().getName());
        //多个代理
        new Thread(web,"码畜").start();
        new Thread(web,"码农").start();
        new Thread(web,"码蟥").start();
    }
}

class Web12306 implements Runnable{
    //票数
    private int ticketNums = 99;

    @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--);
        }
    }
}

一般来说 资源只有一份,进程堵塞的时候,会加大出现问题的情况,会出现负数和重复的情况,这个问题使用线程同步或者锁来进程解决,下面会讲到。

3) Join()方法

Join() 称为合并线程,又称插入进程。让本线程直接到就绪状态等待CPU的调用,进而到运行状态,会让其他进程到堵塞状态。

package com.feng.state;

public class ch07_BlockedJoin01 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            for(int i=0;i<100;i++) {
                System.out.println(Thread.currentThread().getName()+i);
            }
        }) ;
        t.start();

        for(int i=0;i<100;i++) {
            if(i%20==0) {
                try {
                    t.join();  //  线程插队 ,,main 被阻塞了
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
}

4) Yield()

Yield() 称为礼让线程,也就是让当前正在执行的线程暂停。从行状态转入就绪状态。让cpu重新调度。
它也是一个静态方法,再那里调用,哪个线程就礼让当前进程。

package com.feng.state;

public class ch05_YieldDemo01 {
    public static void main(String[] args) {
        new Thread(new MyYield(), "a").start();
        new Thread(new MyYield(), "b").start();
    }
}
 class MyYield implements Runnable{

     @Override
     public void run() {
         System.out.println(Thread.currentThread().getName()+ "-->start");
         try {
             Thread.sleep(200);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         Thread.yield(); // 礼让
         System.out.println(Thread.currentThread().getName()+ "-->end");
     }
 }

在这里插入图片描述

5) Priority

Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程。线程调 度器按照线程的优先级决定应调度哪个线程来执行。 线程的优先级用数字表示,范围从1到10
• Thread.MIN_PRIORITY = 1
• Thread.MAX_PRIORITY = 10
• Thread.NORM_PRIORITY = 5 使用下述方法获得或设置线程对象的优先级。
• int getPriority();
• void setPriority(int newPriority);
优先级的设定建议在start()调用前
注意优先级低只是意味着获得调度的概率低。并不是绝对先调用优先级高后调 用优先级低的线程。

package com.feng.state;
/**
 * 线程的优先级 1-10
 * 1、NORM_PRIORITY  5 默认
 * 2、MIN_PRIORITY   1
 * 2、MAX_PRIORITY  10
 * 概率 ,不代表绝对的先后顺序
 *
 */
public class ch10_PriorityTest {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getPriority());
        MyPriority  mp = new MyPriority();

        Thread t1 = new Thread(mp,"adidas");
        Thread t2 = new Thread(mp,"NIKE");
        Thread t3 = new Thread(mp,"回力");
        Thread t4 = new Thread(mp,"李宁");
        Thread t5 = new Thread(mp,"双星");
        Thread t6 = new Thread(mp,"puma");
        //设置优先级在启动前
        t1.setPriority(10);
        t2.setPriority(Thread.MAX_PRIORITY);
        t3.setPriority(Thread.MAX_PRIORITY);
        t4.setPriority(Thread.MIN_PRIORITY);
        t5.setPriority(Thread.MIN_PRIORITY);
        t6.setPriority(Thread.MIN_PRIORITY);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
        t6.start();
    }
}
class MyPriority implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
        Thread.yield(); // 礼让线程,将线程 返回到就绪状态。
    }
}

在这里插入图片描述

6) Daemon()

package com.feng.state;

public class ch11_DaemonTest {
    public static void main(String[] args) throws InterruptedException {
        Thread t =new Thread(new God(),"God");
        t.setDaemon(true);//将用户线程调整为守护
        // 执行守护线程
        t.start();
        
        // 执行用户线程
        Thread.sleep(Long.parseLong("1000"));
        new You().start();
    }
}
class You extends Thread{
    @Override
    public void run() {
        Thread.currentThread().setName("You");
        for(int i=1;i<=5;i++) {
            System.out.println("happy life...");
        }
        System.out.println(Thread.currentThread().getName()+":finish");
    }
}
class God implements Runnable{
    @Override
    public void run() {
        for(;true;) {
            System.out.println(Thread.currentThread().getName()+":bless you");
        }
    }
}

3. 常用其他方法


方法功能
isAlive()判断线程是否还活着,即线程是否还未终止
setName()给线程起一个名字
getName()获取线程的名字
currentThread()取得当前正在运行的线程对象,也就是获取自 己本身

这几个方法,上面都演示过,就不单单演示啦,都很常用。

接下来就是线程同步、线程协作:生产者消费者模式、高级主题。直接进入博客列表即可看到

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java冯坚持

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值