JAVA 多线程的详解和使用

学完java的多线程我们可以了解到我们的程序是如何进行的,之前我们所学过的知识都是单线程的

什么是程序、进程、线程(概念性的理解)

程序: 用某种语言编写的一组指令的集合,即是一种静态的代码,静态的对象、

进程: 是程序的一次执行过程,或是正在运行的一个程序,是一个动态的过程。
进程的缺点:内存的浪费,cpu负担

线程:进程可进一步细化为线程,是一个内部的一条执行路径。
若一个进程同一时间并执行多个线程,就是支持多线程的

创建线程的方式一:继承Thread来进行创建线程

/**
 * @Auther:Yuhai
 * @Date:2022/4/10-04-10-22:17
 * @Description:IntelliJ IDEA
 * @version:1.0
 * 多线程的创建,方式1:继承Thread类
 * 创建一个继承于Thread类的子类
 * 重写Thread类的run()方法-->将此线程执行的操作声明在run()方法中
 * 创建Thread类的子类的对象
 * 通过此对象调用Start()
 * <p>
 * 例子: 遍历100以内的所有偶数
 */
//创建一个继承于Thread类的子类

class MyThread extends Thread {
    //重写Thread类的run()方法
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }

    }
}

/*
Thread.currentThread().getName(): 获取当前主线程的名字
 */
public class ThreadTest {
    public static void main(String[] args) {
        //创建Thread类的子类的对象
        MyThread myThread = new MyThread();
        //通过此对象调用Start(),1.启动当前主线程,2.调用当前线程的run()方法。
        myThread.start();
        //问题一:我们不能通过直接调用run()方法启动主线程
        // myThread.run();

        //问题二:在启动一个线程,遍历100以内的偶数,不可以还让已经start()的线程去执行,会报IllegalThreadStateException异常的
        //IllegalThreadStateException非法的线程状态
        //此时我们需要创建一个新的对象

        //想要启动多个线程时,就需要创建多个对象
        MyThread myThread1 = new MyThread();
        myThread1.start();

        //下面的操作,仍然在main线程中执行的
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                // System.out.println(i+"*********main()****************");
                System.out.println(Thread.currentThread().getName() + ":" + i + "*********main()****************");
            }
        }
    }
}

创建多线程的方式二:

        实现Runnable接口来创建多线程

ublic class RunnableTest implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i <10 ; i++) {
            System.out.println("第"+i+"此thread执行");
        }
    }

    public static void main(String[] args) {
        //main作为主线程,所以首先会执行他的
        //创建对象
        RunnableTest rd = new RunnableTest();
        Thread t = new Thread(rd);
        t.start();

        for (int i = 0; i <5 ; i++) {
            System.out.println("main----->"+i);
        }
    }
}

总结:继承Thraed类和实现Runnable接口的比较

实现Runnable接口的方式会比继承Thread类的方式好,理由如下

java是单继承的,应该把继承的位置留给重要的东西,而实现接口实现多线程还是比较常用的,可以避免单继承的风险,而且还可以方便共享同一个资源。

接下来我们上一个练习:

使用多线程方式来遍历100以内的偶数,要求使用以上两种方式

/*
    方法1,继承Thread类来-->重写run方法--->创建对象调用start来进行操作
 */
public class ThreadWork1 {
    public static void main(String[] args) {
        //创建各自的对象,来使用,进行输出
        Test t = new Test();
        t.start();

    }

}

class Test extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName()+i);
            }
        }
    }
}

        

/*
    方法2:实现Runnable接口来进行操作

 */
public class ThreadWork1 implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                System.out.println(i);
            }
        }
    }

    public static void main(String[] args) {
        //创建对象,调用方法
     ThreadWork1 threadWork1 = new ThreadWork1();
     Thread thread = new Thread(threadWork1);
     thread.start();
     //也可以用对象直接调用run
        //threadWork1.run();
    }
}

线程的状态:
    1.新建:当一个Thread类或子类的对象被声明并创建时,新生的线程对象处于新建状态
    
    2.就绪:处于新建状态的线程被start()后,将进入的线程队列等待CPU时间片,此时他已经具备了运行条件,只是没有分配到CPU资源

    3.运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run()方法定义了线程的操作和功能

    4.阻塞:在某种特殊的情况下,被人挂起或执行输入输出的操作时,让出CPU并临时中止自己的执行,进入阻塞状态

    5.死亡:线程完成他的全部工作或线程被提前强制性地中止或出现异常导致

线程的相关的API:

/**
 * @Auther:Yuhai
 * @Date:2022/4/11-04-11-13:01
 * @Description:IntelliJ IDEA
 * @version:1.0
 *
 *Thread常用方法的使用
 *
 * 1.    start() :1.启动当前主线程 2。调用线程的run()方法
 * 2.	run() : 通常需要重写Thread类中的此方法,将创键的线程要操作执行的操作方法声明在此方法中
 * 3.	yield():主动释放当前主线程的执行权
 * 4.	join(): 在线程中插入执行另一个线程,该线程被阻塞,直接插入执行的线程完全执行完毕后,该线程才能继续执行下去
 * 5.	stop(): 过时的方法。当执行此方法时,强制结束当前线程
 * 6. 	sleep(long millitime): 线程休眠 	一段时间
 * 7.	isAlive() ;判断当前线程是否存活
 * 8. 1.getName获取当前线程的名字   2 .serName设置当前线程的名字
 *
 * 线程的优先级
 *      1.MAX_PRIORITY:10
 *      MIN_PRIORITY:1
 *      NORM_PRIORITY:5---->默认的优先级
 *      2.如何获取和设置当前线程的优先级
 *
 *      说明:高优先级的线程要抢占低优先级的cpu执行权,但是只是从概率上讲,高优先级的线程高概率的情况下被执行
 *      ,并不意味着只有当高优先级的线程执行来以后,低优先级的线程才执行
 */
public class ThreadMethodTest implements Runnable {

    @Override
    public void run(){
        //用于输出当前执行线程的信息
        System.out.println("名字:"+Thread.currentThread().getName());
        System.out.println("id:"+Thread.currentThread().getId());
        System.out.println("优先级:"+Thread.currentThread().getPriority());
        System.out.println("状态:"+Thread.currentThread().getState());
        System.out.println("是否存活:"+Thread.currentThread().isAlive());
        System.out.println("所属线程组:"+Thread.currentThread().getThreadGroup());
        System.out.println("该线程组的活动线程数目:"+Thread.activeCount());
        System.out.println("线程信息String:"+Thread.currentThread().toString());
        System.out.println("是否持有锁:"+Thread.holdsLock(this));

        synchronized (this){
            System.out.println("是否持有锁:"+Thread.holdsLock(this));


        }
    }

    public static void main(String[] args) {
        ThreadMethodTest threadMethodTest = new ThreadMethodTest();
        //这是创建线程时起的名字,方便我们获取信息
        Thread thread = new Thread(threadMethodTest,"test");
        thread.setName("线程一");
        threadMethodTest.run();


        try {
            Thread.sleep(1000);//休眠一段时间
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

上机练习

需求说明
– 定义一个线程 A ,输出 1 10 之间的整数,定义一个线程 B ,逆
序输出 1 10 之间的整数,要求线程 A 和线程 B 交替输出
分析
– 使用 sleep() 方法阻塞当前线程
/**
 * @Auther:Yuhai
 * @Date:2022/4/15-04-15-17:17
 * @Description:IntelliJ IDEA
 * @version:1.0
 */

/**
 * 利用睡眠的时间差进行交替输出,此时的代码要在逻辑代码里面,方才能进行交替输出,否则会输出错误。
 * 一个让其停止结束的
 */
public class Demo1 implements Runnable {
    @Override
    public void run() {
        for (int i = 1; i <=10; i++) {
            System.out.println(Thread.currentThread().getName() + "----------" + i);
            try {
                Thread.sleep(1050);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Demo1 d = new Demo1();
        Thread t = new Thread(d, "A线程");
        t.start();

        for (int i = 10; i >= 1; i--) {
            System.out.println(Thread.currentThread().getName() + "B线程" + i);

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

总结:利用休眠的时间差来进行操作,这样也可以进行分开的操作

        

接下来剩下的有线程的同步和通信,我们下一个博客再见!GoodBye.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值