当前位置: 首页> 房产> 建筑 > 国内永久免费服务器_桂林两江四湖属于哪个区_活动营销推广方案_南宁关键词排名公司

国内永久免费服务器_桂林两江四湖属于哪个区_活动营销推广方案_南宁关键词排名公司

时间:2025/7/14 13:49:43来源:https://blog.csdn.net/weixin_37165769/article/details/142498853 浏览次数:0次
国内永久免费服务器_桂林两江四湖属于哪个区_活动营销推广方案_南宁关键词排名公司
什么是线程
  • 线程是程序执行的一条路径, 一个进程中可以包含多条线程
  • 多线程并发执行可以提高程序的效率, 可以同时完成多项工作
CPU核心数和线程数的关系

以前:
六个核心数, 1:1, 一个核心 就是一个线程
单核 一个核心 一个线程

现在:
超线程技术, 1:2 , 六个核心数 = 12个线程
四核 六核 …

安卓处理器跟PC还不太一样
ARM32,ARM64,x86,x64

CPU时间片轮转机制

随机切换机制
进程:操作系统所管理的最少单元
线程:CPU调度的最少单元
CPU时间片轮转机制采用了RR调度算法

进程和线程

进程 > 线程
一个进程至少一个线程 或 多个线程
如果一个进程,还有一个线程没有杀掉,还存活,那么进程还存活 (线程依附进程)

多线程并行和并发的区别
  • 并行就是两个任务同时运行,就是甲任务进行的同时,乙任务也在进行。(需要多核CPU)
  • 并发是指两个任务都请求运行,而处理器只能按受一个任务,就把这两个任务安排轮流进行,由于时间间隔较短,使人感觉两个任务都在运行。
  • 比如我跟两个网友聊天,左手操作一个电脑跟甲聊,同时右手用另一台电脑跟乙聊天,这就叫并行。
  • 如果用一台电脑我先给甲发个消息,然后立刻再给乙发消息,然后再跟甲聊,再跟乙聊。这就叫并发。

并行:四个跑道
并发:10秒钟,服务器的吞吐量。比如十秒钟,多少车流量,多少车跑过去

Java程序运行原理
  • Java命令会启动java虚拟机,启动JVM,等于启动了一个应用程序,也就是启动了一个进程。该进程会自动启动一个 “主线程” ,然后主线程去调用某个类的 main 方法。
JVM的启动是多线程的吗
// Java服务器/*虚拟机线程管理的接口*/
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
/*取得线程信息*/
ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
for(ThreadInfo threadInfo:threadInfos) {System.out.println("["+threadInfo.getThreadId()+"]"+" "+threadInfo.getThreadName());
}

上述代码打印结果:

[6] Monitor Ctrl-Break //监控Ctrl-Break中断信号的
[5] Attach Listener //内存dump,线程dump,类信息统计,获取系统属性等
[4] Signal Dispatcher  // 分发处理发送给JVM信号的线程
[3] Finalizer  // 调用对象finalize方法的线程
[2] Reference Handler//清除Reference的线程
[1] main //main线程,用户程序入口
  • Finalizer Object finalize() 需要资源回收 就复写该方法 把代码写这里面去
  • GC 并不是马上就会有GC,资源需要回收,JVM才会检测到,启用GC
多线程程序实现的方式1
public class Demo2_Thread {/*** @param args*/public static void main(String[] args) {MyThread mt = new MyThread();		//4,创建Thread类的子类对象mt.start();							//5,开启线程,调用run方法for(int i = 0; i < 1000; i++) {System.out.println("bb");}}}class MyThread extends Thread {				//1,继承Threadpublic void run() {						//2,重写run方法for(int i = 0; i < 1000; i++) {		//3,将要执行的代码写在run方法中System.out.println("aaaaaaaaaaaa");}}
}
多线程程序实现的方式2
public class Demo3_Thread {/*** @param args*/public static void main(String[] args) {MyRunnable mr = new MyRunnable();	//4,创建Runnable的子类对象Thread t = new Thread(mr);			//5,将其当作参数传递给Thread的构造函数t.start();							//6,开启线程for(int i = 0; i < 1000; i++) {System.out.println("bb");}}}class MyRunnable implements Runnable {		//1,定义一个类实现Runnable@Overridepublic void run() {						//2,重写run方法for(int i = 0; i < 1000; i++) {		//3,将要执行的代码写在run方法中System.out.println("aaaaaaaaaaaa");}}}
有返回值的多线程
public class MyClass {private static class WorkerThread implements Callable<String> {@Overridepublic String call() throws Exception {System.out.println("do work WorkerThread");Thread.sleep(10000);return "run success";}}public static void main(String[] args) throws Exception {// --- 有返回值  任务不能运行,需要寄托 ThreadWorkerThread workerThread = new WorkerThread();FutureTask<String> futureTask = new FutureTask<>(workerThread);new Thread(futureTask).start();System.out.println("get==="+futureTask.get()); // 阻塞的}
}
thread的好处就是runnable的弊端
  • 继承Thread
    • 好处是:可以直接使用Thread类中的方法,代码简单
    • 弊端是:如果已经有了父类,就不能用这种方法(java是单继承,只能一个父类)
  • 实现Runnable接口
    • 好处是:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口,而且接口是可以多实现的
    • 弊端是:不能直接使用Thread中的方法需要先获取到线程对象后,才能得到Thread的方法,代码复杂
匿名内部类实现线程的两种方式

案例:

public class Demo4_Thread {/*** @param args*/public static void main(String[] args) {//继承Thread类new Thread() {										//1,继承Thread类public void run() {								//2,重写run方法for(int i = 0; i < 1000; i++) {				//3,将要执行的代码写在run方法中System.out.println("aaaaaaaaaaaaaa");}}}.start();											//4,开启线程//实现Runnable接口new Thread(new Runnable() {							//1,将Runnable的子类对象传递给Thread的构造方法public void run() {								//2,重写run方法for(int i = 0; i < 1000; i++) {				//3,将要执行的代码写在run方法中System.out.println("bb");}}}).start();											//4,开启线程}}
多线程获取名字和设置名字
  • 1.获取名字
    • 通过Thread.getName()方法获取线程对象的名字
  • 2.设置名字
    • 通过Thread.setName("李四")设置名字,不推荐在 run函数中设置,线程一般执行东西较多。在start前设置
获取当前线程的对象
  • Thread.currentThread(), 主线程也可以获取
多线程休眠
  • Thread.sleep(毫秒,纳秒)
守护线程
  • setDaemon(), 设置一个线程为守护线程, 该线程不会单独执行, 当其他非守护线程都执行结束后, 自动退出

  • 守护线程在结束时也要有时间缓冲才结束,所以并不一定非守护线程执行完后守护线程就立马结束

案例:

public class Demo4_Daemon {/*** @param args* 守护线程*/public static void main(String[] args) {Thread t1 = new Thread() {public void run() {for(int i = 0; i < 2; i++) {System.out.println(getName() + "...aa.."+i);}}};Thread t2 = new Thread() {public void run() {for(int i = 0; i < 50; i++) {System.out.println(getName() + "...bb.."+i);}}};t2.setDaemon(true);							//设置为守护线程t1.start();t2.start();}}

打印结果:

Thread-0...aa..0
Thread-0...aa..1
Thread-1...bb..0
Thread-1...bb..1
Thread-1...bb..2
Thread-1...bb..3
Thread-1...bb..4
Thread-1...bb..5
Thread-1...bb..6
Thread-1...bb..7
Thread-1...bb..8
Thread-1...bb..9
  • 主线程结束,不管守护线程有没有结束,守护线程都必须结束

public class DaemonThread {public static void main(String[] args) throws InterruptedException {Thread t = new Thread() {@Overridepublic void run() {for (int i = 0; i < 50; i++) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(getName() + "---" + i);}}};t.setDaemon(true); // 设置了守护线程t.start(); // 谁调用的 main, main管了我 我就守护main// 主线程,是为了 等 Thread t 10秒钟Thread.sleep(10000);// 非守护线程  主线程一直在等 Thread t 到底执行完了没有// 走到这里,代表主线程结束,主线程结束,不管t线程有没有结束,t线程都必须结束,因为t线程是守护线程,守护了main}}
加入线程
  • join(), 当前线程暂停, 等待指定的线程执行结束后, 当前线程再继续
  • 把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。
  • join(int), 可以等待指定的毫秒之后继续
public class Demo5_Join {/*** @param args* join(), 当前线程暂停, 等待指定的线程执行结束后, 当前线程再继续*/public static void main(String[] args) {final Thread t1 = new Thread() {public void run() {for(int i = 0; i < 10; i++) {System.out.println(getName() + "...aaaaaaaaaaaaa");}}};Thread t2 = new Thread() {public void run() {for(int i = 0; i < 10; i++) {if(i == 2) {try {//t1.join();t1.join(1);	 //插队指定的时间,过了指定时间后,两条线程交替执行  毫秒} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(getName() + "...bb");}}};t1.start();t2.start();}}
礼让线程
  • yield让出cpu
  • 使当前线程让出CPU占有权,但让出的时间是不可设定的。也不会释放锁资源,所有执行yield()的线程有可能在进入到可执行状态后马上又被执行。
public class Demo6_Yield {/*** yield让出cpu礼让线程*/public static void main(String[] args) {new MyThread().start();new MyThread().start();}}class MyThread extends Thread {public void run() {for(int i = 1; i <= 1000; i++) {if(i % 10 == 0) {Thread.yield();						//让出CPU}System.out.println(getName() + "..." + i);}}
}
设置线程的优先级
  • setPriority()设置线程的优先级, 只是大部分优先一点(不靠谱)
public class Demo7_Priority {/*** @param args*/public static void main(String[] args) {Thread t1 = new Thread(){public void run() {for(int i = 0; i < 100; i++) {System.out.println(getName() + "...aaaaaaaaa" );}}};Thread t2 = new Thread(){public void run() {for(int i = 0; i < 100; i++) {System.out.println(getName() + "...bb" );}}};//t1.setPriority(10);					设置最大优先级 默认是5 最大10 最小1//t2.setPriority(1);t1.setPriority(Thread.MIN_PRIORITY);		//设置最小的线程优先级t2.setPriority(Thread.MAX_PRIORITY);		//设置最大的线程优先级t1.start();t2.start();}}
多线程同步方法
  • 使用synchronized关键字修饰一个方法, 该方法中所有的代码都是同步的
  • 锁可以是任意对象,但不能是匿名对象。因为匿名对象不是同一个对象,也就不是同一把锁

案例(非静态的同步方法):

public class Demo2_Synchronized {/*** @param args* 同步代码块*/public static void main(String[] args) {final Printer2 p = new Printer2();new Thread() {public void run() {while(true) {p.print1();}}}.start();new Thread() {public void run() {while(true) {p.print2();}}}.start();}}class Printer2 {Demo d = new Demo();//非静态的同步方法的锁对象是神马?//答:非静态的同步方法的锁对象是this     谁来调用我this就代表谁的对象//同步方法只需要在方法上加synchronized关键字即可public synchronized void print1() {	System.out.print("1");System.out.print("2");System.out.print("3");System.out.print("4");System.out.print("5");System.out.print("\r\n");}public void print2(this) {//synchronized(new Demo()) {							//锁对象不能用匿名对象,因为匿名对象不是同一个对象synchronized(Printer2.class) {		System.out.print("a");System.out.print("b");System.out.print("c");System.out.print("d");System.out.print("\r\n");}}
}

案例(静态的同步方法):

public class Demo2_Synchronized {/*** @param args* 同步代码块*/public static void main(String[] args) {final Printer2 p = new Printer2();new Thread() {public void run() {while(true) {p.print1();}}}.start();new Thread() {public void run() {while(true) {p.print2();}}}.start();}}class Printer2 {Demo d = new Demo();//静态的同步方法的锁对象是什么?//是该类的字节码对象 .class public static synchronized void print1() {							//同步方法只需要在方法上加synchronized关键字即可System.out.print("1");System.out.print("2");System.out.print("3");System.out.print("4");System.out.print("5");System.out.print("\r\n");}public static void print2() {//synchronized(new Demo()) {							//锁对象不能用匿名对象,因为匿名对象不是同一个对象synchronized(Printer2.class) {		System.out.print("a");System.out.print("b");System.out.print("c");System.out.print("d");System.out.print("\r\n");}}
}
死锁
  • 多线程同步的时候, 如果同步代码嵌套, 使用相同锁, 就有可能出现死锁
    • 尽量不要嵌套使用
private static String s1 = "筷子左";
private static String s2 = "筷子右";
public static void main(String[] args) {new Thread() {public void run() {while(true) {synchronized(s1) {System.out.println(getName() + "...拿到" + s1 + "等待" + s2);synchronized(s2) {System.out.println(getName() + "...拿到" + s2 + "开吃");}}}}}.start();new Thread() {public void run() {while(true) {synchronized(s2) {System.out.println(getName() + "...拿到" + s2 + "等待" + s1);synchronized(s1) {System.out.println(getName() + "...拿到" + s1 + "开吃");}}}}}.start();
}
停止线程
  • 自然终止

要么是run执行完成了,要么是抛出了一个未处理的异常导致线程提前结束。

  • 手动中止

暂停、恢复和停止操作对应在线程ThreadAPI就是suspend()resume()stop()。但是这些API是过期的,也就是不建议使用的。不建议使用的原因主要有:以suspend()方法为例,在调用后,线程不会释放已经占有的资源(比如锁),而是占有着资源进入睡眠状态,这样容易引发死锁问题。同样,stop()方法在终结一个线程时不会保证线程的资源正常释放,通常是没有给予线程完成资源释放工作的机会,因此会导致程序可能工作在不确定状态下。正因为suspend()resume()stop()方法带来的副作用,这些方法才被标注为不建议使用的过期方法。

安全的中止则是其他线程通过调用某个线程A的interrupt()方法对其进行中断操作, 中断好比其他线程对该线程打了个招呼,“A,你要中断了”,不代表线程A会立即停止自己的工作,同样的A线程完全可以不理会这种中断请求。因为java里的线程是协作式的,不是抢占式的。线程通过检查自身的中断标志位是否被置为true来进行响应,线程通过方法isInterrupted()来进行判断是否被中断,也可以调用静态方法Thread.interrupted()来进行判断当前线程是否被中断,不过Thread.interrupted()会同时将中断标识位改写为false

如果一个线程处于了阻塞状态(如线程调用了thread.sleepthread.jointhread.wait、),则在线程在检查中断标示时如果发现中断标示为true,则会在这些阻塞方法调用处抛出InterruptedException异常,并且在抛出异常后会立即将线程的中断标示位清除,即重新设置为false

不建议自定义一个取消标志位来中止线程的运行。因为run方法里有阻塞调用时会无法很快检测到取消标志,线程必须从阻塞调用返回后,才会检查这个取消标志。这种情况下,使用中断会更好,因为,一、一般的阻塞方法,如sleep等本身就支持中断的检查,二、检查中断位的状态和检查取消标志位没什么区别,用中断位的状态还可以避免声明取消标志位,减少资源的消耗。

注意:处于死锁状态的线程无法被中断


import java.text.SimpleDateFormat;
import java.util.Date;/***类 说明:抛出InterruptedException异常的时候,要注意中断标志位*/
public class HasInterrputException {private static SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss_SSS");private static class UseThread extends Thread{public UseThread(String name) {super(name);}@Overridepublic void run() {String threadName = Thread.currentThread().getName();while(!isInterrupted()) { try {System.out.println("UseThread:"+formater.format(new Date()));Thread.sleep(3000);} catch (InterruptedException e) { // sleep 会把中断信号清除System.out.println(threadName+" catch interrput flag is "+isInterrupted()+ " at "+(formater.format(new Date())));// TODO interrupt 需要在此内部 调用才能中断了,才能把被清楚的标记修改成trueinterrupt();e.printStackTrace();}System.out.println(threadName);}System.out.println(threadName+" interrput flag is " +isInterrupted());}}public static void main(String[] args) throws InterruptedException {Thread useThread = new UseThread("HasInterrputEx");useThread.start();System.out.println("Main:"+formater.format(new Date()));Thread.sleep(800);System.out.println("Main begin interrupt thread:"+formater.format(new Date()));useThread.interrupt(); // 被 InterruptedException e 人家清除}}
深入理解run()和start()

Thread类是Java里对线程概念的抽象,可以这样理解:我们通过new Thread()其实只是new出一个Thread的实例,还没有操作系统中真正的线程挂起钩来。只有执行了start()方法后,才实现了真正意义上的启动线程。
start()方法让一个线程进入就绪队列等待分配cpu,分到cpu后才调用实现的run()方法,start()方法不能重复调用。
而run方法是业务逻辑实现的地方,本质上和任意一个类的任意一个成员方法并没有任何区别,可以重复执行,可以被单独调用。

总结

run 和start的区别 ?

答:run是函数调用 和线程没有任何关系, .start会走底层 会走系统层 最终调度到 run函数,这才是线程。

如何控制线程的执行顺序 ?

答:join来控制 让t2获取执行权力,能够做到顺序执行

多线程中的并行和并发是什么?

答:四个车道,四辆车并行的走,就是并行, 四个车道中,五秒钟多少的车流量,多少的吞吐量一样

在Java中能不能指定CPU去执行某个线程?

答:不能,Java是做不到的,唯一能够去干预的就是C语言调用内核的API去指定才行,这个你回答的话,面试官会觉得你研究点东西

在项目开发过程中,你会考虑Java线程优先级吗?

答:不会考虑优先级,为什么呢? 因为线程的优先级很依赖与系统的平台,所以这个优先级无法对号入座,无法做到你想象中的优先级,属于不稳定,有风险
因为某些开源框架,也不可能依靠线程优先级来,设置自己想要的优先级顺序,这个是不可靠的
例如:Java线程优先级又十级,而此时操作系统优先级只有2~3级,那么就对应不上

sleep和wait又什么区别?

答:sleep是休眠,等休眠时间一过,才有执行权的资格,注意:只是又有资格了,并不代表马上就会被执行,什么时候又执行起来,取决于操作系统调度
wait是等待,需要人家来唤醒,唤醒后,才有执行权的资格,注意:只是又有资格了,并不代表马上就会被执行,什么时候又执行起来,取决于操作系统调度
含义的不同:sleep无条件可以休眠, wait是某些原因与条件需要等待一下(资源不满足)

在Java中能不能强制中断线程的执行?

答:虽然提供了 stop 等函数,但是此函数不推荐使用,为什么因为这种暴力的方式,很危险,例如:下载图片5kb,只下载了4kb 等
我们可以使用interrupt来处理线程的停止,但是注意interrupt只是协作式的方式,并不能绝对保证中断,并不是抢占式的

如何让出当前线程的执行权?

答:yield方法,一般只在JDK某些实现才能看到,是让出执行权

sleep,wait,到底那个函数才会 清除中断标记?

答:sleep在抛出异常的时候,捕获异常之前,就已经清除

关键字:国内永久免费服务器_桂林两江四湖属于哪个区_活动营销推广方案_南宁关键词排名公司

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: