如何自己建站网站制作,百度seo报价,如何在godaddy空间做手机网站,长春网络优化最好的公司线程 前言线程的由来线程是什么线程的属性线程更高效的原因举个例子#xff08;线程便利性的体现#xff09; 多线程代码线程并发执行的代码jconsole(观测多线程) 线程的调度问题创建线程的几种方法1#xff09;通过继承Thread 重写run2#xff09;使用Runnable接口 重写ru… 线程 前言线程的由来线程是什么线程的属性线程更高效的原因举个例子线程便利性的体现 多线程代码线程并发执行的代码jconsole(观测多线程) 线程的调度问题创建线程的几种方法1通过继承Thread 重写run2使用Runnable接口 重写run 有利于解耦合3匿名内部类4Runnable匿名内部类5Lambda表达式 总结 前言
线程的由来
现如今的CPU存在多个核心因此能够同时处理多个进程我们也称为并发执行(并行并发)。通过这样的“多进程模式”能够很好的利用多核CPU极大的提升了效率。 但是多进程的编程虽然好用但也会带来一些问题。 在服务器中需要给多个客户端提供服务如果同时来了多个客户端如此一来只能用多个进程处理这件事情。这样会导致服务器频繁进行创建销毁进程的操作这是极其影响效率的。 于是引入了轻量级进程——线程。线程的创建和开销会小的多。
线程是什么
线程可以理解为“线程的一部分”一个进程中可以包含多个线程。 在进程中存在PCB结构体一个PCB代表着一个线程而一个进程由多个PCB构成若干个PCB联合在一起描述了一个进程。举个例子来说进程像是一个小区而线程就是一个个住在小区里的人。
线程的属性
因为线程存在与进程中因此他们共用一个PCB为了区分线程之间的区别设置了一个新的概念词tgid(tgd)。同一个进程的tgid是相同的而pid是不同的线程们共用同一份内存指针和文件描述符表。 因为线程们共用内存资源和文件资源的原因线程之间可以访问到彼此的数据。而每个线程都是在独立的CPU上调度执行。因此我们可以认为线程是系统调度执行的基本单位进程是系统资源分配的基本单位。
线程更高效的原因
进程在创建和销毁过程中需要进行资源分配和资源释放的过程而线程存在于进程中线程之间共用资源在线程创建和销毁的过程中可以省略资源分配/释放的步骤省去了申请资源的过程因此线程是更高效更轻量级的一种进程。
举个例子线程便利性的体现
现在有一项任务需要完成我们可以选择创建一个进程来解决如果这个任务太繁重了我们可以选择创建多个进程来分担压力。这种方法好是好但是进程的创建和销毁会占用到资源造成资源的浪费。 但是现在我们学过线程了我们可以选择在进程中创建多个线程同时通过多核CPU的特点让线程可以达到并发执行的效果这样既不会有申请资源的烦恼又能高速高效的执行任务可谓是一举多得鼓掌 当然说归说我们不能想到这么方便直接在进程中创建多个线程叠罗汉不就好了这肯定是不对的。俗话说的好物极必反。如果我们一味的引入自然会引发其他的问题且听下回分解
多线程代码
在JVM中已经对线程封装好了即Thread类。我们可以通过Thread类实现线程的创建。接下来我写一份简单的代码进行演示
class MyThread extends Thread {Overridepublic void run() {System.out.println(hello thread);}
}
public class ThreadDemo1{public static void main(String[] args) {Thread t new MyThread();t.start();}
}如何理解这段代码呢首先创建了MyThread类并继承Thread方法实现动态绑定。接着重写Thread的run方法run()方法中包含的是线程t要执行的方法而t.start()方法是启动线程t的方法。这段代码中有两个线程t线程和main线程。由此我们可以知道在学习线程之前的代码中只存在着一个线程main线程。同时我们也称main线程为主线程。 当然run()是start()创建出来的线程在线程里被调用的run()方法已经创建好而不去手动调用将这个方法交给系统/其他的库调用即“回调函数”。
线程并发执行的代码
或许在上面的代码中我们不能很好的看出来t线程和main线程是怎么体现并发执行的因此这边我分别在两个线程中加入两个循环以求更好的体现出线程并发执行的特点。
class MyThread extends Thread {Overridepublic void run() {while (true){System.out.println(hello thread);}}
}
public class ThreadDemo1{public static void main(String[] args) {Thread t new MyThread();t.start();while (true){System.out.println(hello main);}}
}在这里我们也看到了 “hello thread” 和 hello main线程在控制台上交替打印这也代表着两个线程正在并发执行。
jconsole(观测多线程)
jconsole是java的一款观测线程的实用工具我已在其他文章中编写好需要的可以观看下面的文章。 jconsole的简单使用
线程的调度问题
在上面的线程循环代码中我们已经可以证明多线程是并发执行的。 那么他们执行的顺序是否存在规律呢 我们可以使用Thread.sleep()方法进行简单的观测。
Thread.sleep()可以设置时间使线程停止接下来的工作使线程进入休眠状态阻塞。在规定的时间过后线程继续运行执行未完成的任务。代码如下
class MyThread extends Thread {Overridepublic void run() {while (true){System.out.println(hello thread);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
public class ThreadDemo1{public static void main(String[] args) {Thread t new MyThread();t.start();while (true){System.out.println(hello main);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}部分运行结果如下 从这部分运行结果我们可以看出来线程的运行使无序的。在操作系统中也称之为**“抢占式执行”。任何一个线程在执行到任何一个代码的过程中都可能被其他的线程抢占掉它的cpu资源于是cpu就给别的线程执行了。 如果是这样的结果显然这样的抢占式执行充满了随机性执行效果难以预测甚至可能引入bug。**这肯定是程序猿们不想看到的这涉及到了线程的安全问题。
创建线程的几种方法
1通过继承Thread 重写run
在上面的代码中已经展示这边不再赘述。2使用Runnable接口 重写run 有利于解耦合
在Runnable接口中我们可以通过查看源码看到其中只有一个抽象类方法run()因此Runnable的作用就是描述一个任务一个行为。**无论是线程还是其他方法执行run()这个方法都是可以的**。通过Runnable方法实现的多线程有一个好处解耦合。 在第一种写法中线程重写自己的run()方法以及线程调用的都是自己本身的方法而使用Runnable方法之后在后续进行代码的改动将会降低成本。 下面给出一个举例
class MyRunnable implements Runnable{Overridepublic void run() {while (true){System.out.println(hello runnable);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
public class ThreadDemo2{public static void main(String[] args) {Thread t new Thread(new MyRunnable());t.start();while (true){System.out.println(hello main);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}3匿名内部类
继承Thread 重写run,创建Thread的子类不知名同时也创建了一个不具名子类实例。我们看看下面的代码
public class ThreadDemo3{public static void main(String[] args) {Thread t1 new Thread(){Overridepublic void run() {System.out.println(使用匿名内部类);}};t1.start();}
}4Runnable匿名内部类
与Thread匿名内部类的写法类似在new Runnable之后直接重写Runnable的方法这也创建了一个实例不知名实现了Runnable接口的方法。 演示代码如下
public class ThreadDemo4 {public static void main(String[] args) {Thread t1 new Thread(new Runnable() {Overridepublic void run() {System.out.println(匿名内部类使用Runnable);}});t1.start();System.out.println(hello main);}
}5Lambda表达式
通过使用lambda表达式代替需要重写的run方法。
public class ThreadDemo5 {//lambda表达式//lambda本质上也是一个匿名函数用完就丢public static void main(String[] args) {Thread t new Thread(() -{while (true){System.out.println(hello thread);}});t.start();System.out.println(hello main);}
}总结
线程是一个轻量级进程能够很大程度上节约成本和资源在开发中有着十分重要的作用。同样的引入多线程意味着我们需要解决一些引入所带来的问题。如线程安全问题这是随着我们逐渐深入了解所需要做的。 需要源码的可以点击链接线程代码 有帮助到大家的请三连~感谢