线程初识及如何创建线程,常用构造方法和属性

二、线程阶段一

1.线程(Thread)概念

一个线程就是一个执行流,每个线程之间都可以按照自己的顺序执行自己的代码,多个线程之间也就执行这多份代码。简单来讲线程它就类似于厂里面的生产线。

2.多线程编程和多进程编程都能满足“并发编程”需求场景,那我们为什么要使用多线程编程呢?

进程是比较“重量的”速度慢,消耗资源多,在创建、销毁、调度进程的时候成本都是比较高的,虽然进程它可以解决并发编程的问题,但它不是一个高效的选择(就好比上面我说过的两个特别优秀的同学,都是满分,但是一个用时10分钟,一个用时30分钟,很明显我们选择的是用时最少的)。

那进程为什么会是重量的呢?这里主要是体现在资源分配操作上,比如说我们要给进程分配一块内存,系统就需要遍历自己的空闲内存的表,找到一个大小差不多的空间进行资源分配。同时如果有很多进程都在申请系统资源,那么在进行资源分配时候就得一个一个来,很明显是浪费了很多时间的。

而线程它则是更轻量的进程,约定,一个进程中可以包含多个线程,每个线程都是一个独立可以调度执行的执行流,这些执行流之间本身就是并发的,同时这些线程共用同一份进程的系统资源,也就是说对于线程来讲,系统资源是已经分配好了,所以在创建、销毁、调度线程都比进程的更快。

所以说操作系统真正调度的是在调度线程,而不是进程,线程是操作系统调度运行的基本单位,进程是操作系统分配资源的基本单位

3.进程和线程之间的区别

(1)进程包含线程,每个进程至少有一个线程存在,即主线程(工厂和流水线)

(2)进程有自己独立的空间和文件描述符表,同一个进程中的各个线程之间共享同一个地址空间和文件描述符表。进程和进程之间不共享内存空间。

(3)进程是操作系统分配资源的基本单位,线程是操作系统调度执行的基本单位。

(4)进程之间具有独立性,一个进程挂了,不会影响别的进程,同一个进程里的多个线程之间,一个线程挂了,可能会把整个进程带走,影响到其它线程的。

4.Java进行线程编程

Java标准库提供了一个类Thread表示一个线程,下面是感受多线程程序和普通程序的区别:

package notebook;


class MyThread extends Thread {
    @Override
    public void run() {

        while (true) {
            System.out.println("多线程线程");
        }
    }
}
public class ThreadTest01 {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        //开启线程
        myThread.start();

        while (true) {
            System.out.println("主线程");

        }

    }
}

在这里插入图片描述
可以看出每个线程都是一个独立的执行流,并且多个线程之间是并发执行的。同时我们可以看到打印的结果也是无序的,随机的,这里的话表示的是两个线程都是同时执行的,但是打印结果肯定是有先有后的,因为是两个线往同一个控制台上打印,所以同一个控制台必须得顺序输出,这也就出现了我们的看到了无序的这种打印结果。

5.使用jconsole命令观察线程

前提我们得把程序跑起来!!!
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们可以看到当前我们的线程Thread-0,还有我们的主线程main情况。

package notebook;


class MyThread extends Thread {
    @Override
    public void run() {

        while (true) {
            System.out.println("多线程线程");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class ThreadTest01 {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        //开启线程,start创建线程
        myThread.start();
        //start会创建新的线程
        //run不会创建新的线程,run是在main线程中执行的,入口的方法
        //run是特殊方法,可以被自动调用,对于普通方法,需要手动调用
//        myThread.run();
        while (true) {
            System.out.println("主线程");
        }

    }
}

上面的run方法不是一个随便的方法,它是重写了父类的方法。在我们使用thread.start()时候它会调用操作系统的api,创建新线程,新的线程里调用thread.run();。

此处的sleep是Thread的静态方法,等多少时间后在执行。

6.线程的创建
(1)继承Thread类,重写run方法
package notebook;

class Mythread1 extends Thread {
    @Override
    public void run() {
        System.out.println("hello");
    }
}

public class ThreadTest02 {
    public static void main(String[] args) {
        Mythread1 mythread1 = new Mythread1();
        mythread1.start();
        System.out.println("world");
    }
}

在这里插入图片描述

(2)实现Runnable接口,重写run方法
package notebook;


class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("hello");
    }
}
public class ThreadTest03 {
    public static void main(String[] args) {
        //创建Thread实例,调用Thread的构造方法时将Runnable对象作为target参数
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();

        System.out.println("Runnable接口实现线程");

    }
}

在这里插入图片描述
第一种写法是使用Thread的run描述线程入口

第二种是使用Runnable interface来描述线程入口

所以说两个写法没有本质区别

(3)继承Thread类,使用匿名内部类
package notebook;

public class ThreadTest04 {
    public static void main(String[] args) {
        Thread thread = new Thread() {
            @Override
            public void run() {

                while (true) {
                    try {
                        System.out.println("使用匿名内部类创建Thread子类对象");
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };

        thread.start();

        while (true) {
            try {
                System.out.println("主线程");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在这里插入图片描述

(4)实现Runnable接口,使用匿名内部类
package notebook;

public class ThreadTest05 {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        System.out.println("实现Runnable接口,使用匿名内部类");
                        Thread.sleep(3000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        thread.start();
        while (true) {
            try {
                System.out.println("主线程");
                Thread.sleep(3000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

在这里插入图片描述

(5)lambda表达式(推荐写法)
package notebook;

public class ThreadTest06 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
           while (true) {
               System.out.println("使用lambda表达式创建线程");
               try {
                   Thread.sleep(3000);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
        });

        thread.start();
        while (true) {
            System.out.println("主线程");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在这里插入图片描述
lambda表达式,本质上是一个匿名函数,基本写法:() -> {}

()里面放参数,如果只有一个可以省略

{}里面放函数体,只有一行代码,也可以省略

7.多线程的优势——>增加运行速度

这里通过并发和串行方式计算变量的值,看计算的时间长短进行验证。

System.nanoTime()记录当前系统的纳秒级时间戳

serial串行的完成一系列运算,concurrency使用两个线程并行的完成同样的运算

package notebook;


/**
 * 多线程的优势——》增加运算速度
 */
public class ThreadTest07 {
    public static final long count = 10_0000_0000;

//    并发方式
    public static void concurrency() throws InterruptedException{
//        开始时间
        long begin = System.nanoTime();
//        通过线程计算a的值
        Thread thread = new Thread(() -> {
            int a = 0;
            for (long i = 0; i < count; i++) {
                a--;
            }
        });

        thread.start();

        //主线程种计算b的值
        int b = 0;
        for (long i = 0; i < count; i++) {
            b--;
        }
//        等待thread结束后在开始进行
        thread.join();//这里的话要抛异常,在main线程种,调用thread.join表示是让main线程等待thread结束,再往下执行,

//        统计时间
        long end = System.nanoTime();//最后计算完成后的时间
        //1.0转换为浮点类型,/1000/1000转换为毫秒
        double resulttime = (end - begin) * 1.0 / 1000 / 1000;
        System.out.println("并发计算时间:" + resulttime + "毫秒");

    }

    //串行方式,在主线程中进行计算
    public static void serial() {
        long begin = System.nanoTime();
        int a = 0;
        for (long i = 0; i < count; i++) {
            a--;
        }

        int b = 0;
        for (long i = 0; i < count; i++) {
            b--;
        }
        long end = System.nanoTime();
        double resulttime = (end - begin) * 1.0 / 1000 / 1000;
        System.out.println("串行计算时间:" + resulttime + "毫秒");
    }
    public static void main(String[] args) throws InterruptedException{
        concurrency();
        serial();
    }
}

在这里插入图片描述

8.Thread类及常见方法

Thread类是JVM用来管理线程的一个类,也就是说每个线程都有一个唯一的Thread对象与之关联。

(1)常见的构造方法
public class ThreadTest08 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (true) {
                System.out.println("Thread()");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        System.out.println("常见构造方法:Thread()");
    }
}
class MyRunnables implements Runnable {
    @Override
    public void run() {
        while (true) {
            try {
                System.out.println("Thread(Runnable target)");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class ThreadTest09 {
    public static void main(String[] args) {
        MyRunnables myRunnables = new MyRunnables();
        Thread thread = new Thread(myRunnables);
        thread.start();

        System.out.println("使用Runnable对象创建线程对象");
    }

}
package notebook;


public class ThreadTest10 {
    public static void main(String[] args) {
        Thread thread = new Thread("线程1") {
            @Override
            public void run() {
                while (true) {
                    System.out.println("我是线程1");
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        thread.start();
        while (true) {
            System.out.println("创建线程对象,并命名");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

同样的对于创建线程对象,并且命名,Thread(String name),我们可以通过上述说的jconsole去查看我们的线程名字:
在这里插入图片描述

package notebook;

public class ThreadTest11 {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    System.out.println("使用Runnable对象创建线程对象,并命名");
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        },"线程2");

        thread.start();

        while (true) {
            System.out.println("主线程");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

在这里插入图片描述

package notebook;

public class ThreadTest12 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while(true) {
                System.out.println("lambda表达式创建线程,并命名");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"线程3");

        thread.start();

        while(true) {
            System.out.println("主线程");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在这里插入图片描述

(2)Thread的几个常见属性

在这里插入图片描述
代码示例:

package notebook;

public class ThreadTest13 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 10; i++) {

                try {
                    System.out.println(Thread.currentThread().getName() + "啦啦啦");
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + "我的名字叫线程1");
        },"线程1");

        System.out.println(Thread.currentThread().getName() + ":ID:" + thread.getId());

        System.out.println(Thread.currentThread().getName() + ":名称:" + thread.getName());

        System.out.println(Thread.currentThread().getName() + ":状态:" + thread.getState());

        System.out.println(Thread.currentThread().getName() + ":优先级:" + thread.getPriority());

        System.out.println(Thread.currentThread().getName() + ":是否是后台线程:" + thread.isDaemon());

        System.out.println(Thread.currentThread().getName() + ":是否存活:" + thread.isAlive());

        System.out.println(Thread.currentThread().getName() + ":是否被中断:" + thread.isInterrupted());

        thread.start();

        while (thread.isAlive()) {
            try {
                System.out.println(Thread.currentThread().getName() + ":状态:" + thread.getState());
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在这里插入图片描述
以上就是对线程的初步学习啦,主要就是为什么要使用多线程编程,如何创建线程,如何通过jconsole去观察线程,线程的常见构造方法使用,即常见属性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小哈不会玩

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

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

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

打赏作者

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

抵扣说明:

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

余额充值