05 多线程的创建

多线程
重难点 线程的创建 4中方法 线程同步(线程安全,锁)3种方法

内存结构图:
在这里插入图片描述
类加载器把class文件加载进来
数据加载到内存中
方法区和堆是一个进程一份,进程的线程共享方法区和堆。资源共享带来安全隐患。虚拟机栈和程序计数器是一个线程一份,

cpu的核数从操作系统来看,看到的是物理核数的2倍。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

多线程创建

方式一 继承Thread类
package com.shangguigu;

/**
 * 多线程创建,方式一:继承Thread类
 * 1. 创建一个子类继承于Thread类
 * 2. 子类里面重写run()方法,用于执行我们需要的功能
 * 3. 创建Thread子类的对象
 * 4. 通过此对象调用start()
 * 例子:遍历100以内的偶数---写在run方法里面
 * @author wangshengnan
 * @create 2020-10-02-11:02
 */
public class ThreadTest {
    public static void main(String[] args) { //psvm创建main快捷键
        MyThread myThread = new MyThread();//alt + enter 创建实例
        myThread.start();//start()的两个作用:1 启动当前线程;2调用当前线程的run方法
        //问题一:我们不能通过直接调用run()的方式启动分线程
        //myThread.run();如果是调run()不调用start()也不会报错,调用run的仍然是主线程,没有启动分线程; 可以通过 打印Thread.currentThread().getName();查看详细结果;
        //问题二:同一个线程只能start一次,myThread()启动了一次不能再次调用start启动,线程有状态,没启动的时候是0 ,启动之后就不再是0 ,已经启动的线程再次启动就会抛出异常 IllegalThreadState
        //正确的操作是重新new一个线程对象,再去启动
		//如下操作在主线程种执行
        for (int i = 0; i < 500; i++) {
            System.out.println(i+"*********main*********"); //i.sout打印i
        }
    }
}


class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0){
                System.out.println(i); //i.sout打印i
            }
        }
    }
}

执行结果部分截图:正如结果所示,启动分线程之后主线程和分线程并发运行。
在这里插入图片描述
练习

package com.shangguigu.practice;

/**
 * 多线程练习题: 创建两个分线程,一个遍历100以内的偶数,一个遍历100以内的奇数
 * 方法一 创建两个Thread的子类  Thread1 Thread2比较麻烦
 * 方法二 创建匿名子类,适用子类只用一次之后不再使用
 * @author wangshengnan
 * @create 2020-10-02-11:54
 */
public class ThreadPrac {
    public static void main(String[] args) {
        /**
         * 方法一
         * Thread1 thread1 = new Thread1();
         *         Thread2 thread2 = new Thread2();
         *         thread1.start();
         *         thread2.start();
         */
        //方法二:
        new Thread(){  //匿名子类,直接在里面重写run方法,实现遍历偶数
            @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();
    }
}

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

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

关于Thread类的常用方法

package com.shangguigu;

/**
 * Thread类的常用方法
 * 1. start()方法 用于启动分线程,并调用当前线程的run方法
 * 2. run() 通常许需要重写Thread类中的此方法,将创建的线程要执行的曹祖声明在此方法中
 * 3. currentThread() 是静态方法,返回执行当前代码的线程
 * 4. getName() 返回当前线程的名字
 * 5. setName() 设置当前线程的名字
 * 6. yield() 释放此线程当前cpu的执行权,当然释放完之后cpu会调配线程,这个线程有可能再次抢到cpu的执行权。
 * 7. join()  在线程a或主线程中调用线程b的join()方法,线程a就进入阻塞状态,直到线程b完全执行完之后,a才结束阻塞状态。
 * 8. sleep(long millitime) 毫秒 1s = 1000mills,这里是线程进入阻塞状态,阻塞mills时间后等待cpu分配资源,分配到再执行
 * 9. isAlive()
 * @author wangshengnan
 * @create 2020-10-02-12:15
 */
public class ThreadMethodTest {
    public static void main(String[] args) {
        Thread1 thread1 = new Thread1("线程:*1*");
        //thread1.setName("线程一"); //修改线程的名字方法一setName
        thread1.start();

        Thread.currentThread().setName("主线程"); //给主线程命名
        for (int i = 0; i < 100; i++) {
            for (int j = 0; j < 100; j++) {
                if(i % 2 != 0){
                    System.out.println(i);
                }
            }
            if(i == 20){
                try {
                    thread1.join();  //在主线程里调用分线程的join方法,意思是主线程进入阻塞,等待分线程完全执行完毕后解除阻塞,再去执行。
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            thread1.isAlive(); //这里肯定是false 因为 上面的代码thread1已经执行完成了
        }

    }
}

class Thread1 extends Thread{
    @Override
    public void run(){  //关于抛异常,Thread1是继承Thread 如果Thread类里面run方法没有抛异常,这里也不能抛异常
        for (int i = 0; i < 100; i++) {
            if(i % 2 == 0){
                try {
                    sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+":"+i);

            }
            if(i % 20 == 0){
                yield();  //这里如果i能整除20 线程释放cpu,等待cpu重新分配,当然重新分配之后可能还是这个线程执行。
            }
        }
    }
    //方法二使用构造函数给线程名字,前提是Thread类里面是有给名字赋值的构造函数
    public Thread1(String name){
        super(name);
    }

}

join()方法,意思就是红色线程不再执行,等待蓝色线程执行完成之后再去执行红色线程。
在这里插入图片描述

线程调度

在这里插入图片描述
优先级
MAX_PRIORITY:10
MIN_PRIORITY:1
NORM_PRIORITY: 5 默认的优先级
优先级的设置
setPriority(int p)
Thread.currentThread().setPriority();
getPriority()
优先级高的抢占低优先级的,只是从概率上讲,高优先级抢占的概率更高,但是不一定就是高优先级比低优先级的先执行。

方式二 实现Runnable接口方式

静态变量是共享资源,

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值