目录

1、线程与进程

2、什么是多线程

3、多线程的实现

4、设置和获取线程名称

5、线程的休眠:正在执行的线程休眠(暂时停止执行)

6、线程阻塞

7、线程中断

8、守护线程

9、线程不安全问题

10、线程安全1------同步代码块

11、线程安全2------同步方法

12、显式锁

13、公平锁与非公平锁(大厂爱问面试题)

14、线程死锁

15、多线程通信问题

16、带返回值的线程Callable(了解即可)

17、线程池的介绍(类似于存放线程的数组)

18、线程池------缓存线程池

19、线程池------定长线程池

20、线程池------单线程线程池

21、线程池------周期定长线程池

22、Lambda表达式(函数式编程思想)


1、线程与进程

进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间。

线程:是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行,一个进程至少有一个线程。(线程实际上是在进程基础之上的进一步划分,一个进程启动之后,里面的若干执行路径又可以划分成若干个线程)

2、什么是多线程

其实通俗易懂的来说,多线程技术就是可以让一个程序同时做多件事,比如你打开音乐软件,它既可以播放音乐,又可以滚动歌词,又可以显示图片。这些功能都是同时进行的,而不需要像运行代码一样一行一行的排队进行。

3、多线程的实现

首先,创建多线程有两(三)种方法:1、继承Thread。2、实现Runnable接口(3、实现Callable接口(了解,不常用))

//实现runnable与继承Tread相比有如下优势:
//1、通过创建任务,然后给线程分配的方式来实现的多线程。更适合多个线程同时执行相同任务的情况
//2、可以避免单继承带来的局限性。
//3、任务与线程本身是分离的,提高了程序的健壮性。
//4、线程池技术,接受Runnable类型的任务,不接受Thread类型的线程。
但Thread也有好处,可以用匿名内部类

实现Runnable:

先写两个类来实现Runnable接口!作为线程的运行对象!


public class MyRunnable implements Runnable{  //写一个MyRunnable类来实现Runnable接口@Overridepublic void run() {   //实现Run方法for(int i = 0;i<3;i++){System.out.println("床前明月光"+i);}}
}
class MyRunnable2 implements Runnable{    //写一个haha类来实现Runnable接口@Overridepublic void run() {for(int i = 0;i<3;i++){System.out.println("hahahaha"+i)}}
}

创建多线程并且运行。

public class Demo {public static void main(String[] args) {//创建一个对象MyRunnable r = new MyRunnable();//创建第二个对象MyRunnable2 r2 = new MyRunnable2();//创建两个线程,将对象分别传进去Thread t1 = new Thread(r);Thread t2 = new Thread(r2);//开启线程t1.start();t2.start();
//用匿名内部类来创建一个线程
//匿名内部类:创建一个类不起名字但是指认了父类为Thread,并且创建了对象:new的MyRunnable()对象,只调用一次start方法new Thread (new MyRunnable()).start(); //再继续写一个循环作为main的主线程for (int i=0;i<3;i++){System.out.println("疑是地上霜"+i);}}
}

运行结果:我们易发现 :一共执行了四段线程(抢占式执行)

4、设置和获取线程名称

1、设置线程名称一共有两种方法:

1.1:在启动线程之前设置名称,设置名称用setName方法!(补充于上面的代码案例)

public class Demo {public static void main(String[] args) {//创建一个对象MyRunnable r = new MyRunnable();//创建第二个对象MyRunnable2 r2 = new MyRunnable2();//创建两个线程,将对象分别传进去Thread t1 = new Thread(r);Thread t2 = new Thread(r2);//设置线程名称t1.setName("线程一");   //线程一设置名称t2.setName("线程二");   //线程二设置名称//开启线程t1.start();t2.start();
//用匿名内部类来创建一个线程
//匿名内部类:创建一个类不起名字但是指认了父类为Thread,并且创建了对象:new的MyRunnable()对象,只调用一次start方法new Thread (new MyRunnable()).start(); //再继续写一个循环作为main的主线程for (int i=0;i<3;i++){System.out.println("疑是地上霜"+i);}}
}

1.2:在new线程时设置名称

public class Demo {public static void main(String[] args) {//创建一个对象MyRunnable r = new MyRunnable();//创建第二个对象MyRunnable2 r2 = new MyRunnable2();//创建两个线程,将对象分别传进去Thread t1 = new Thread(r,"线程一");    //创建线程时设置名称Thread t2 = new Thread(r2,"线程二");   //创建线程时设置名称//开启线程t1.start();t2.start();
//用匿名内部类来创建一个线程
//匿名内部类:创建一个类不起名字但是指认了父类为Thread,并且创建了对象:new的MyRunnable()对象,只调用一次start方法new Thread (new MyRunnable(),"新方法名字").start(); //再继续写一个循环作为main的主线程for (int i=0;i<3;i++){System.out.println("疑是地上霜"+i);}}
}

2.获取线程名称:

Thread.currentThread().getName()

currentThread()获取当前线程,getName获取名称

注:打印线程名称的代码应写在线程中,而不是main方法中。在执行线程的时候打印。

运行结果:设置了名称并且获取打印了出来

注:如果不设置名称,线程也会有自己的名称。eg:

5、线程的休眠:正在执行的线程休眠(暂时停止执行)

有两种方法:一个是指定休眠的毫秒数,一个是指定休眠的毫秒+纳秒数。

  • static void sleep​(long millis)

    导致当前正在执行的线程休眠(暂时停止执行)指定的毫秒数,具体取决于系统计时器和调度程序的精度和准确性。

    static void sleep​(long millis, int nanos)

    导致当前正在执行的线程休眠(暂时停止执行)指定的毫秒数加上指定的纳秒数,具体取决于系统定时器和调度程序的精度和准确性。

for (int i=0;i<10;i++){System.out.println(i);Thread.sleep(1000);   //休眠1000毫秒=1秒}

如此段代码可以实现:每输出一个i便暂停一秒后再输出下一个i

6、线程阻塞

所有消耗时间的操作都为线程阻塞,如:读取某个文件,接收用户输入,线程休眠等。

7、线程中断

线程不能通过人为的方式强行中断,因为一个线程在开启后有它自己的任务,会占用很多资源,一旦被外部因素中断,很可能无法释放资源。从而产生很多内存垃圾。所以一个线程是否结束,要由其本身来决定。于是我们通过给线程打标记的方式来提示线程该中断了,线程发现标记后会抛出异常,由程序员在catch块中提供解决方法。

我们现来实现一个功能:主线程(main)走完后,结束线程,其他线程中断。

实现思路:在主线程中想要结束Thread线程的地方,用interrupt来打标记

在Thread线程中每次休眠时都会检查自身是否携带中断标记(必须有休眠或等待)。如果有,则跳入catch块,由程序员来设计进一步的解决。(有中断标记不代表会中断,只是会跳入catch块)

源码:

先写一个Thread线程:

public class MyRunnable implements Runnable{@Overridepublic void run() {for (int i=0;i<6;i++){System.out.println(Thread.currentThread().getName()+i);try {Thread.sleep(1000); //在每次休眠时都会检查是否有中断标记} catch (InterruptedException e) {  //检查到有中断标记跳入catch块,程序员做新一步处理System.out.println("应该中断");return; //中断}}}
}

main函数中:

Thread t1 = new Thread(new MyRunnable()); //new一个线程t1.start();  //开启Thread线程//主线程:for (int i=0;i<3;i++){System.out.println(Thread.currentThread().getName()+i);Thread.sleep(1000);}//主线程结束后,给Thread线程打中断标记t1.interrupt();  //中断标记

运行结果:主线程执行完后,经检查,立刻中断其他线程,而不再输出Thread4、5了。有Thread2、3是因为在检查到中断标记到中断之间,其它线程还可以抢占着执行。

8、守护线程

线程:守护线程和用户线程

用户线程:当一个进程不包含任何存活的用户线程时,进程结束。

守护线程:守护用户线程的,依附于用户线程,没有用户线程时,守护线程也结束。

eg:我们现在将Thread线程设置为守护线程,main线程结束时,Thread线程也结束。

方法:setDaemon(true)

Thread线程:

public class MyRunnable implements Runnable {@Overridepublic void run() {for (int i=0;i<10;i++){System.out.println(Thread.currentThread().getName()+i);try {Thread.sleep(1000); //为了让Thread执行慢一点,采用休眠} catch (InterruptedException e) {}}}
}

main线程:注:必须要在Thread线程启动之前!!设置Thread为守护线程

public static void main(String[] args) {MyRunnable r = new MyRunnable();Thread t1 = new Thread(r);t1.setDaemon(true);  //在启动之前设置t1为守护线程t1.start();for (int i=0;i<3;i++){System.out.println(Thread.currentThread().getName()+i);}t1.interrupt();}

9、线程不安全问题

线程由于是抢占式执行,所以在多线程同时执行时,很容易发生线程不安全的问题。下面,我们举一个例子,来分析一下如何不安全。

我们浅写一个卖票系统:

public class Demo1 {public static void main(String[] args) {Runnable r = new Ticket();  //创建一个类对象,一个对象多个线程new Thread(r).start();  //创建一个线程new Thread(r).start();  //创建一个线程new Thread(r).start();  //创建一个线程}static class Ticket implements Runnable{  //卖票类int count = 10;@Overridepublic void run() {while (count>0){System.out.println("准备卖票...");count--;System.out.println("出票成功!"+count);}}}
}

执行结果:我们发现存在负数和相同数字的情况,这是为什么呢?

原理:线程为抢占式执行,如果现在只剩一张票,那么可能在A线程刚判断完count>0还没有执行count--时,B和C也判断>0就进入了循环。于是便出现了负数的情况。这就是线程不安全问题!

10、线程安全1------同步代码块

通过加锁的方式让线程排队执行从而达到线程安全的效果。加锁范围可以很窄,一行就可以加锁。

关键字:synchronized(锁对象){}

{}中的内容为加锁内容,需排队执行,(锁对象:java中的任何对象都可以作为锁对象)

实现原理:一个线程进入大括号内,将上锁。执行完后,锁解开。剩下的线程抢占锁

改变上面的卖票代码:在线程启动前(run上面)上锁,循环将会排队执行:

执行结果:排队执行,不再出现负数与相同数字的情况。

11、线程安全2------同步方法

同步代码块可以在很小的范围加锁,而同步方法即是在一个方法上加锁。

同步方法关键字:synchronized修饰方法

我们对最初的卖票代码进行修改:

public class Demo2 {public static void main(String[] args) {Runnable r = new Ticket();  //创建一个类对象,一个对象多个线程new Thread(r).start();  //创建一个线程new Thread(r).start();  //创建一个线程new Thread(r).start();  //创建一个线程}static class Ticket implements Runnable {  //卖票类int count = 10;@Overridepublic void run() {  //线程同步启动while (true) {sale();if (!sale()){  //如果卖票方法返回false证明票售空,跳出循环break;}}}public synchronized boolean sale(){  //抽出卖票方法,线程排队走方法if (count > 0) {System.out.println("准备卖票...");/* try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}*/count--;System.out.println(Thread.currentThread().getName() + "出票成功!" + count);return true;}return false;}}
}

synchronized修饰方法,给方法加锁。线程排队走方法。

12、显式锁

上面两种,同步方法或者同步代码块都是隐式锁,而显示锁就是用lock类的子类Reentrantlock创建对象,自己来锁,自己来解锁。

13、公平锁与非公平锁(大厂爱问面试题)

我们知道线程遇到锁后需排队等待锁开。而公平锁其实就是排队执行,等待锁开后,先来的线程先执行。而非公平锁是,锁一旦打开,所有线程一块抢,谁抢到谁执行。我们刚刚描述的三种方法都是非公平锁。

公平锁的实现:

private Lock l = new ReentrantLock(true);  //()里面写true即为公平锁

14、线程死锁

线程死锁指的是两个线程中加锁的方法套在了一起,互相要调用,线程一由于线程二加锁了,无法调用线程二的方法,于是自己无法走完解锁,线程二要调用线程一的方法,而自己线程由于没有走完还未解锁,于是线程一也无法调用自己的方法。两个线程便死锁了,都无法解锁。

举例说明:

写两个类:罪犯类与警察类

 static class Culprit{  //罪犯类public synchronized void say(Police p){  //加锁方法System.out.println("罪犯:你放了我,我就放了人质");p.fun();  //调用警察方法}public synchronized void fun(){   //加锁方法 System.out.println("我放了人质,警察也放了我");}}static class Police{  //警察类public synchronized void say(Culprit c){    //加锁方法System.out.println("警察:你放了罪犯,我就放过你");c.fun();   //调用罪犯方法}public synchronized void fun(){    //加锁方法System.out.println("我救了人质,罪犯跑了");}}

写一个子线程:

static class MyRunnable implements Runnable {  //线程类Culprit culprit = new Culprit();Police police = new Police();public MyRunnable(Culprit culprit,Police police){this.culprit = culprit;this.police = police;}@Overridepublic void run() {police.say(culprit);  //在子线程中用警察调用say,想得到罪犯的fun方法回应}}

main方法+写主线程:

public static void main(String[] args) {Culprit culprit = new Culprit();Police police = new Police();new Thread(new MyRunnable(culprit,police)).start();  //new子线程culprit.say(police);  //主线程用罪犯调用say,想得到警察的fun方法回应}

运行结果易出现死锁情况:

都没有得到相应的回应,发生此情况的原因:

在主线程启动后,罪犯调用了say方法,此时子线程启动了。子线程便锁住,主线程就无法得到警察的fun方法回应。得不到回应,主线程就没有执行完,便不会解锁。不解锁,那么子线程的警察也无法得到罪犯的fun方法回应,也无法解锁。所以死锁。。

不死锁的情况:

原因:主线程执行过程中子线程没有开启。所以主线程成功调用方法,执行完后解锁。子线程再开启。互不冲突。

如何避免死锁情况发生?

在调用一个有锁的方法时,尽量不调用另一个有锁的方法。(听起来像废话,但确实如此。)

15、多线程通信问题

假设我们现在有一个厨师,一个服务员,一个盘子。这三者的工作关系应该为:厨师做饭时,服务员等待,做好后,厨师唤醒服务员,服务员端走,厨师等待,服务员把盘子端回来,唤醒厨师。厨师做菜,服务员等待。

如果没有“等待”与“唤醒”,那么极可能发生错乱,例如厨师刚改了菜名,还没有改味道,服务员就把盘子端走了,厨师连做两道或服务员连着端菜等问题。

那我们在代码中如何实现“等待”和“唤醒”呢?

使用:关键字:

this.notifyAll(); //唤醒其它等待线程
this.wait();  //自己等待

厨师类:

   public static class Cooker extends Thread {private Food f;public Cooker(Food f) {this.f = f;}@Overridepublic void run() {for (int i = 0; i < 100; i++) {if (i % 2 == 0) {System.out.println("厨师做菜:铁板鱿鱼,香辣味");f.setNameAndTaste("铁板鱿鱼", "香辣味");} else {System.out.println("厨师做菜:章鱼小丸子,酸甜味");f.setNameAndTaste("章鱼小丸子", "酸甜味");}}}}

服务员类:

 public static class Waiter extends Thread {private Food f;public Waiter(Food f) {this.f = f;}@Overridepublic void run() {for (int i = 0; i < 100; i++) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}f.getNameAndTaste();}}}

食物类:食物类中有两个方法:

方法一为厨师用的设置菜名与味道方法。

方法二为服务员用的获得菜名与味道方法。

厨师在调用方法一时,让服务员线程等待。调用完毕后,唤醒其它线程(服务员线程),并且让自己等待。

服务员在调用方法二时,让厨师线程等待,用完毕后,唤醒其它线程(厨师线程),并且让自己等待。

源码:

public static class Food {private String name;private String taste;//boolean flag = true; 用flag来标记,true表示做饭,false表示端饭public synchronized void setNameAndTaste(String name, String taste) {//  if (flag) {  (只是为了多一层执行判断,与线程等待无关)this.name = name;try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}this.taste = taste;//         }// flag = false;this.notifyAll();  //唤醒其它线程的等待try {this.wait(); //自己等待} catch (InterruptedException e) {e.printStackTrace();}}public synchronized void getNameAndTaste() {// if (!flag) {System.out.println("服务员端走的菜是:" + name + "," + taste);// flag = true;this.notifyAll(); //唤醒其它线程的等待try {this.wait();  //自己等待} catch (InterruptedException e) {e.printStackTrace();}//}}}

main方法:

 public static void main(String[] args) {Food f = new Food();new Cooker(f).start();  //启动厨师线程new Waiter(f).start();  //启动服务员线程}

四个代码块合并为整个代码。

16、带返回值的线程Callable(了解即可)

使用步骤:

详细方法移步API

17、线程池的介绍(类似于存放线程的数组)

线程执行一个任务时,流程是:创建线程---创建任务---执行任务---关闭线程。而其实创建线程和关闭线程都是很耗时的,可能你的任务只有两三行代码,但是你就要创建一个线程,因为并发的线程很多,所以频繁的大量创建线程,会大大降低系统的效率。而线程池就是一个容纳多个线程的容器,池中的线程可以反复调用,省去了频繁创建线程对象的操作,节省了大量的时间和资源。

Java中的四种线程池:

1、缓存线程池:

执行流程:

①判断线程池是否存在空闲线程

②有则使用

③无则创建线程,放入线程池再使用

2、定长线程池(长度是指定的数值)

执行流程:

①判断线程池是否存在空闲线程

②存在则使用

③不存在空闲线程,且线程池未满的情况则创建线程并放入线程池,然后使用。

④不存在空闲线程,且线程池已满的情况则等待线程池有空闲线程,再使用

3、单线程线程池(效果与定长线程池创建时传入数值1的效果是一样的)

执行流程:

①判断线程池是否存在空闲线程

②存在则使用

③不存在,则等待池中的单个线程空闲了,再使用

4、周期性任务定长线程池

接收到任务后,可在触发后执行,可在规定多少秒之后执行,也可以是多少秒执行一次,间隔周期重复执行。

执行流程:

①判断线程池是否存在空闲线程

②存在则使用

③不存在空闲线程,且线程池未满的情况则创建线程并放入线程池,然后使用。

④不存在空闲线程,且线程池已满的情况则等待线程池有空闲线程,再使用

18、线程池------缓存线程池

创建方法:

ExecutorService service = Executors.newCachedThreadPool(); //获取缓存线程池service.execute(new Runnable() {     //在线程池中加一个任务@Override                   括号内为任务public void run() {     System.out.println(Thread.currentThread().getName()+"锄禾日当午");}
});

示例:创建一个缓存线程池,并创建三个任务

public static void main(String[] args) {ExecutorService service = Executors.newCachedThreadPool(); //获取缓存线程池service.execute(new Runnable() {     //在线程池中加一个  任!务!(不是线程)@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "锄禾日当午");}});service.execute(new Runnable() {  //在线程池中加一个  任!务!(不是线程)@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "汗滴禾下土");}}); service.execute(new Runnable() {  //在线程池中加一个  任!务!(不是线程)@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "谁知盘中餐");}});}

结果:线程池创建了三个线程,同时执行

此时我们在第三个线程后面使用休眠一秒钟,以保证三个线程都执行完毕。(此时线程池中有三个空闲线程)

在此后我们在new一个新的任务

    try {Thread.sleep(1000);   //休眠一秒钟} catch (InterruptedException e) {e.printStackTrace();}service.execute(new Runnable() {   //创建新任务@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"谁知盘中餐");}});

运行结果:第四个任务,用的是线程池中的三个空闲线程中的一个,而没有new新的线程~

19、线程池------定长线程池

创建方法:

ExecutorService service = Executors.newFixedThreadPool(2);//此线程池有两个线程
service.execute(new Runnable() {     //在线程池中加一个任务@Override                   括号内为任务public void run() {     System.out.println(Thread.currentThread().getName()+"锄禾日当午");}
});

创建了三个任务,而线程池中只有两个线程。

 public static void main(String[] args) {ExecutorService service = Executors.newFixedThreadPool(2);//此线程池有两个线程service.execute(new Runnable() {@Overridepublic void run() {  //一个任务System.out.println(Thread.currentThread().getName()+"我要进大厂");try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"进行结束");}});service.execute(new Runnable() {@Overridepublic void run() {  //一个任务System.out.println(Thread.currentThread().getName()+"我要买摩托车");try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"进行结束");}});service.execute(new Runnable() {  //一个任务@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"月入18k");}});}

结果:我们可以清楚的看到,前两个任务并发执行,执行完后,才有空余的线程,执行第三个任务

20、线程池------单线程线程池

相当于定长线程池传参为1,创建方法

ExecutorService service = Executors.newSingleThreadExecutor();

无论创建多少任务,始终只有这一个线程在运行。

单线程应用:当有任务需要用子线程来完成,但需排队完成时,可用单线程技术。

剩下与以上相同,不再赘述。

21、线程池------周期定长线程池

创建方法:

ScheduledExecutorService service = Executors.newScheduledThreadPool(2) //参数为几个线程

返回值不同于前面:返回类型为ExecutorService的子类ScheduledExecutorService。

一共有两个方法:

方法一:定时执行一次,传入三个参数:执行的任务,延迟时长数字,数字的单位

此段代码意思: 两秒后执行任务,只执行一次

方法二:周期性执行任务,传入四个参数:任务,延迟的时长,周期的时长,时长的单位

此段代码意思:五秒后执行任务,每间断五秒执行一次任务。

22、Lambda表达式(函数式编程思想)

面向对象编程是new对象,再用对象调用方法。Java1.8版本提出了Lambda函数式编程思想。指:不用对象,直接实现方法。下面我们来举例子:

现在我们自己写了一个接口,写了一个方法。我们要用此print方法,应该怎么用?

static interface Mymath{  //自己写一个接口int sum(int x,int y);  //想用lambda,就只能有一个方法}public static void print (Mymath m,int x,int y){  //另写一个方法System.out.println(x+y);}

我们应该在main函数中:new对象,实现方法。

 public static void main(String[] args) {Mymath m = new Mymath() {  //new一个Mymath类的对象@Overridepublic int sum(int x, int y) { //实现里面的方法return x+y;}};print(m,100,200);  //用print函数,传入参数}

那其实我们new对象也只是为了用Mymath中的int sum(int x,int y)方法。

所以用lambda编程,省去new对象:在main函数中直接用方法:

print为要用的方法,print后的外层()中为函数的参数,第一个()为接口Mymath中函数的参数,-> 后面的 { } 中为Mymath中的函数的内容,后面继续为print的剩下两个参数。

 public static void main(String[] args) {print((int x,int y) -> {return x+y;},100,200);}

本文到这里,多线程技术就全部介绍完毕了。

作者码字不易,您的点赞收藏是对我的鼓励~

多线程技术(全面介绍)相关推荐

  1. android progressbar 不显示_Android多线程技术选型最全指南(1)

    码个蛋(codeegg) 第 935 次推文 作者:qing的世界 链接:https://juejin.im/post/5d1eb4acf265da1bb003de71 前言 前段时间在组内做了一下现 ...

  2. 多线程_C# 多线程技术

    这节讲一下多线程(Thread)技术. 在讲线程之前,先区分一下程序,进程,线程三者的区别,大体上说,一个程序可以分为多个进程,一个进程至少由一个线程去执行,它们是层层包含的关系.我们写的程序,就是一 ...

  3. [转]《英特尔多核/多线程技术》

    Technorati 标签: 多核,多线程,intel 原文地址:http://software.intel.com/zh-cn/articles/32067/ 提示:相关章节的电子版请到原文地址页下 ...

  4. 微软MFC技术简明介绍

    我是荔园微风,作为一名在IT界整整25年的老兵,今天来看一下微软MFC技术简明介绍 Visual C++ 与 MFC 微软公司于1992年上半年推出了C/C++ 7.0 产品时初次向世人介绍了MFC ...

  5. 云计算运营—03 KVM虚拟化技术方案介绍

    KVM虚拟化技术方案介绍 1.背景介绍 KVM(Kernel-based Virtual Machine) 开源全虚拟化方案 支持体系结构 x86(32位,64位).IA64.PowerPC.S390 ...

  6. java编写的王八程序_利用JAVA多线程技术模拟龟兔赛跑.doc

    利用JAVA多线程技术模拟龟兔赛跑 摘要:该文介绍了利用JAVA语言的多线程技术,对"龟兔赛跑"寓言故事的模拟.从模拟程序的具体设计思路,到详细的实现过程,将技术的应用融入到一个有 ...

  7. Java多线程技术解析

    Java多线程技术 1.多线程的概述 1.1.进程与线程 进程是操作系统进行资源分配和调度的一个独立单位,它是一个内存中运行的应用程序的载体,每个进程都有一个独立的内存空间.进程一般由程序,数据集合和 ...

  8. java游戏 动态录入弹球_动态弹球的实现 加入了多线程技术--javaSE游戏准备工作...

    任务描述:实现了动态弹球的功能,对于有弹球功能的SE游戏奠定了基础. package 运用线程技术的小球; import java.awt.*; import java.awt.event.*; im ...

  9. JAVA基础 多线程技术学习笔记(V1.0)

    目录 一.多线程介绍 1.1 多线程中的基本概念 1.1.1多线程与进程 1.1.2 进程.线程的区别和联系 1.1.3 并发和并行的区别 1.1.4   线程的执行特点 1.1.5 主线程与子线程 ...

最新文章

  1. mysql存储过程写法—动态参数运用
  2. 写给正在入坑linux系统的伙伴
  3. Attention To, Convert To Capped Collection
  4. django-restframework使用
  5. Http协议(7)—Http缓存
  6. 设计模式(第十七式:迭代器模式)
  7. C++(7)--for循环,break,continue语句
  8. [POJ 2503] Babelfish【二分查找】
  9. vue项目 pc端自适配方案
  10. 关于高级交互设计师的5个经验总结
  11. python伪装ip地址_python伪造ip
  12. 互联网金融牌照有哪些 金融牌照一览表
  13. ps 改变图层纯色与渐变色
  14. Seq2Seq模型中的集束搜索(Beam Search)
  15. ue4vr插件_UE4虚幻引擎可视化VR实例3dsMax全流程中级教学
  16. 清除DataGridView的全部内容,包括标题行
  17. 以低功耗蓝牙便携医疗设备帮助改善癫痫患者治疗管理
  18. Day7 String类
  19. ORALCE 创建主键唯一约束同时也创建索引
  20. iOS15使用带Header的tableview 顶部出现空白问题

热门文章

  1. 安卓中备份和恢复短信
  2. 宁可累死在路上,也绝不闲死在家里
  3. XSS基础及实战(XSS提取cookie并登录的)
  4. MQTT安装部署手册
  5. linux原生系统_超详细:Ubuntu全套软件生态系统使用展示
  6. python如何使用gpu_如何使用GPU加速numpy运算
  7. 计算机网络ip地址计算,知道IP地址怎么算网络地址? 网络地址的推算方法
  8. java后台怎么获取系统时间_Java 后台获取当前时间
  9. 悟空CRM 5.0 升级发布
  10. 明码(蛇皮解法)——第九届蓝桥杯C语言B组(省赛)第二题