Java多线程之线程创建

一、程序、进程与线程的理解:

1、程序(program):

是为完成特定任务、用某种语言编写的一组指令的集合。
即指一段静态的代码,静态对象。

2、进程(process):

是程序的一次执行过程, 或是正在运行的一个程序。
是一个动态的过程:有它自身的产生、存在和消亡的过程,即生命周期。
(1)例如:运行中的QQ,运行中的MP3播放器。
(2)程序是静态的,进程是动态的。
(3)进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域。

3、线程(thread):

进程可进一步细化为线程,是一个程序内部的一条执行路径。
(1)若一个进程同一时间并行执行多个线程,就是支持多线程的。
(2)线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc),线程切换的开销小。
(3)一个进程中的多个线程共享相同的内存单元/内存地址空间:
它们从同一堆中分配对象,可以访问相同的变量和对象。
这就使得线程间通信更简便、高效。但多个线程操作共享的系统资源可能就会带来安全的隐患。

二、单核CPU与多核CPU的理解:

1、单核CPU:

其实是一种假的多线程,因为在一个时间单元内,也只能执行一个线程的任务。
例如:虽然有多车道,但是收费站只有一个工作人员在收费,只有收了费才能通过,
那么CPU就好比收费人员。如果有某个人不想交钱,那么收费人员可以把他“挂起”。
但是因为CPU时间单元特别短,因此感觉不出来。

2、多核CPU:

如果是多核的话,才能更好的发挥多线程的效率。 (现在的服务器都是多核的)
在一个Java应用程序java.exe, 其实至少有三个线程:main()主线程、gc()、垃圾回收线程、
异常处理线程。当然如果发生异常,会影响主线程。

三、并行与并发的理解:

1、并行:多个CPU同时执行多个任务。比如多个人同时做不同的事。
2、并发:一个CPU(采用时间片)同时执行多个任务。比如秒杀、多个人做同一件事。

四、多线程的理解:

1、背景:

以单核CPU为例, 只使用单个线程先后完成多个任务(调用多个方法),
肯定比用多个线程来完成用的时间更短,为何仍需多线程呢?

2、多线程程序的优点:

(1)提高应用程序的响应。对图形化界面更有意义,可增强用户体验。
(2)提高计算机系统CPU的利用率。
(3)改善程序结构。将既长又复杂的进程分为多个线程,独立运行,利于理解和修改。

3、何时需要多线程:

(1)程序需要同时执行两个或多个任务。
(2)程序需要实现一些需要等待的任务时,如用户输入、文件读写操作、网络操作、搜索等。
(3)需要一些后台运行的程序时。

五、线程的创建和使用:

1、Thread类的特性:
(1)每个线程都是通过某个特定Thread对象的run()方法来完成操作的,经常把run()方法的主体称为线程体
(2)通过该Thread对象的start()方法来启动这个线程,而非直接调用run()。
(3)Java语言的JVM允许程序运行多个线程,它通过java.lang.Thread类来体现。

2、Thread类构造器:
(1)Thread():创建新的Thread对象。
(2)Thread(String threadname):创建线程并指定线程实例名。
(3)Thread(Runnable target):指定创建线程的目标对象,它实现了Runnable接口中的run方法。
(4)Thread(Runnable target, String name):创建新的Thread对象。

3、Thread类成员方法:
●void start():启动线程,并执行对象的run()方法。
●run():线程在被调度时执行的操作。
●String getName():返回线程的名称。
●void setName(String name):设置该线程名称。
●static Thread currentThread():返回当前线程。
在Thread子类中就是this,通常用于主线程和Runnable实现类。
●static void yield():线程让步。
暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程。
若队列中没有同优先级的线程,忽略此方法。
●join():当某个程序执行流中调用其他线程的join()方法时,调用线程将被阻塞,
直到join()方法加入的join线程执行完为止。低优先级的线程也可以获得执行。
●static void sleep(long millis):(指定时间:亳秒)。
令当前活动线程在指定时间段内放弃对CPU控制,使其他线程有机会被执行,时间到后重排队。
抛出InterruptedException异常。

4、API中创建线程的两种方式:
继承Thread类的方式、实现Runnable接口的方式。
方式一:继承Thread类
(1)定义子类继承Thread类。
(2)子类中重写Thread类中的run方法。
(3)创建Thread子类对象,即创建了线程对象。
(4)调用线程对象start方法:启动线程,调用run方法。

 1 //例子:遍历100以内的所有的偶数
 2 //1. 创建一个继承于Thread类的子类
 3 class MyThread extends Thread {
 4     //2. 重写Thread类的run()
 5     @Override
 6     public void run() {
 7         for (int i = 0; i < 100; i++) {
 8             if(i % 2 == 0){
 9                 System.out.println(Thread.currentThread().getName()
10                         + ":" + i);
11             }
12         }
13     }
14 }
15
16 public class ThreadTest {
17     public static void main(String[] args) {
18         //3. 创建Thread类的子类的对象
19         MyThread t1 = new MyThread();
20
21         //4.通过此对象调用start():启动当前线程、调用当前线程的run()
22         t1.start();
23         //问题一:我们不能通过直接调用run()的方式启动线程。
24         //t1.run();
25
26         //问题二:再启动一个线程,遍历100以内的偶数。
27         // 不可以还让已经start()的线程去执行。会报IllegalThreadStateException
28         //t1.start();
29         //我们需要重新创建一个线程的对象
30         MyThread t2 = new MyThread();
31         t2.start();
32
33         //如下操作仍然是在main线程中执行的。
34         for (int i = 0; i < 100; i++) {
35             if(i % 2 == 0){
36                 System.out.println(Thread.currentThread().getName()
37                         + ":" + i + "***********main()************");
38             }
39         }
40     }
41 }

注意事项:
1、如果自己手动调用run()方法,那么就只是普通方法,没有启动多线程模式。
2、run()方法由JVM调用,什么时候调用,执行的过程控制都有操作系统的CPU调度决定。
3、想要启动多线程,必须调用start方法。
4、一个线程对象只能调用一次star()方法启动,如果重复调用了,
则将抛出以上的异常“llegalThreadStateException"。

方式二:实现Runnable接口
(1)定义子类,实现Runnable接口。
(2)子类中重写Runnable接口中的run方法。
(3)通过Thread类含参构造器创建线程对象。
(4)将Runnable接口的子类对象作为实际参数传递给Thread类的构造器中。
(5)调用Thread类的start方法:开启线程,调用Runnable子类接口的run方法。

 1 //1. 创建一个实现了Runnable接口的类
 2 class MThread implements Runnable{
 3     //2. 实现类去实现Runnable中的抽象方法:run()
 4     @Override
 5     public void run() {
 6         for (int i = 0; i < 100; i++) {
 7             if(i % 2 == 0){
 8                 System.out.println(Thread.currentThread().getName()
 9                         + ":" + i);
10             }
11
12         }
13     }
14 }
15
16 public class ThreadTest1 {
17     public static void main(String[] args) {
18         //3. 创建实现类的对象
19         MThread mThread = new MThread();
20         //4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
21         Thread t1 = new Thread(mThread);
22         t1.setName("线程1");
23         //5. 通过Thread类的对象调用start():启动线程、
24         // 调用当前线程的run()-->调用了Runnable类型的target的run()
25         t1.start();
26
27         //再启动一个线程,遍历100以内的偶数
28         Thread t2 = new Thread(mThread);
29         t2.setName("线程2");
30         t2.start();
31     }
32 }

比较创建线程的两种方式:
开发中:优先选择实现Runnable接口的方式。
1、 实现的方式没有类的单继承性的局限性。
2.、实现的方式更适合来处理多个线程有共享数据的情况。
联系:public class Thread implements Runnable
相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()中。

原文地址:https://www.cnblogs.com/ZengBlogs/p/12203181.html

时间: 2024-10-08 19:01:53

Java多线程之线程创建的相关文章

Java多线程系列-线程创建

1.怎样创建多线程? Java从语言级别实现多线程,因此实现一个多线程程序很easy.有两种方法能够实现多线程,即继承Thread类和实现Runnable接口.由于Java不支持多继承的原因,建议尽可能通过实现Runnable接口实现多线程. 使用Runnable接口实现多线程有例如以下长处: 1.能够避免由于Java的单继承特性而带来的局限. 2.增强程序的健壮性.代码能够被多个线程共享.代码与数据是独立的: 3.适合多个同样程序代码的线程区处理同一资源的情况. 两者之间的不同: *Threa

Java多线程:如何创建线程?

在前面一篇文章中已经讲述了在进程和线程的由来,今天就来讲一下在Java中如何创建线程,让线程去执行一个子任务.下面先讲述一下Java中的应用程序和进程相关的概念知识,然后再阐述如何创建线程以及如何创建进程.下面是本文的目录大纲: 一.Java中关于应用程序和进程相关的概念 二.Java中如何创建线程 三.Java中如何创建进程 若有不正之处,请多多谅解并欢迎批评指正. 请尊重作者劳动成果,转载请标明原文链接: http://www.cnblogs.com/dolphin0520/p/391351

Java多线程之线程的同步

Java多线程之线程的同步 实际开发中我们也经常提到说线程安全问题,那么什么是线程安全问题呢? 线程不安全就是说在多线程编程中出现了错误情况,由于系统的线程调度具有一定的随机性,当使用多个线程来访问同一个数据时,非常容易出现线程安全问题.具体原因如下:   1,多个线程同时访问一个数据资源(该资源称为临界资源),形成数据发生不一致和不完整.   2,数据的不一致往往是因为一个线程中的多个关联的操作(这几个操作合成原子操作)未全部完成. 关于线程安全问题,有一个经典的情景:银行取钱.代码如下: /

Java多线程之线程的控制

Java多线程之线程的控制 线程中的7 种非常重要的状态:  初始New.可运行Runnable.运行Running.阻塞Blocked.锁池lock_pool.等待队列wait_pool.结束Dead 如果将"锁池"和"等待队列"都看成是"阻塞"状态的特殊情况,那么可以将线程归纳为5个状态: 新建,就绪,运行,阻塞,死亡. ┌--------------------< 阻塞 ↓                    (1)(2)(3)  

Java多线程之线程的通信

Java多线程之线程的通信 在总结多线程通信前先介绍一个概念:锁池.线程因为未拿到锁标记而发生的阻塞不同于前面五个基本状态中的阻塞,称为锁池.每个对象都有自己的锁池的空间,用于放置等待运行的线程.这些线程中哪个线程拿到锁标记由系统决定.前面我们也有T到死锁的概念,线程互相等待其他线程释放锁标记,而又不释放自己的:造成无休止地等待.当出现死锁的时候,我们应该如何解决呢?通过线程间的通信解决. 线程间通信: 多线程之间的通信有2种方式,第一种是使用object类的几个方法,第二种是使用条件变了来控制

Java多线程之线程结束清理

该事例说明了清理工作必须要放在finally块中 package Thread.Interrupting; import java.util.concurrent.TimeUnit; class NeedsCleanup { private final int id; public NeedsCleanup(int ident) { id = ident; System.out.println("NeedsCleanup " + id); } public void cleanup()

Java多线程之线程中断

该例子说明,Sleep可以被中断,但是I/O和synchronized不能被中断. package Thread.Interrupting; import java.io.IOException; import java.io.InputStream; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; imp

java多线程之线程的同步与锁定(转)

一.同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 例如:两个线程ThreadA.ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据. publicclass Foo { privateint x = 100; publicint getX() { return x;     } publicint fix(int y) {         x = x - y; return x;     } } publicclass MyRunnable i

java多线程之 ---- 线程死锁

java多线程之线程死锁 产生死锁的主要原因: 因为系统资源不足. 进程运行推进的顺序不合适. 资源分配不当等. 如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁.其次, 进程运行推进顺序与速度不同,也可能产生死锁. 产生死锁的四个必要条件:  互斥条件:一个资源每次只能被一个进程使用. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放. 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺. 循环等待条件:若干进