Java中多线程的学习和使用(一)概述及创建方式

转载请注明http://www.cnblogs.com/devtrees/p/4395477.html

多线程的学习

一.多线程概述

(一).进程与线程

在说多线程或者线程之前,让我们来了解一下更显而易见的进程概念。那什么是进程呢?

进程就是正在进行中的程序。

Windows操作系统中在任务栏处右击,弹出的菜单中可看见任务管理器,打开它,就可以看见当前运行的程序和进程列表。

进程:是一个正在执行中的程序。

每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。

线程:就是进程中的一个独立的控制单元。

线程在控制进程的执行。

一个进程中至少有一个线程。

无论是qq还是迅雷,只要他们启动程序,就会在内存中开辟一段空间,产生地址值,进程就是用于标注这段空间的,用于封装里面的控制单元。

当出现’’java.lang.NoClassDefFoundError:com/sun/tools/javac/main’’错误的时候,证明java程序找不到tools.jar文件,也就是说环境变量有可能配置不对,或源文件丢失。

Java VM启动时就会有一个进程java.exe,该进程中至少有一个线程负责java程序的执行,而且这个线程运行的代码存在于main方法中。该线程称之为主线程。

扩展:其实更细节说明jvm,jvm不止一个线程,还有负责垃圾回收机制的线程。

有多条执行路径的程序,我们就称之为多线程程序。

多线程存在的意义。

同时进行,提高效率。

如何在我们的程序中自定义多线程程序。

通过对api的查找,java已经提供了对线程这类事物的描述。

Java.lang包下有一个Thread类,用于创建程序中的执行线程。就是用于描述控制单元这样d额一个对象。jVM允许应用程序并发地运行多个执行线程。

创建方式:

一种是将类声明称Thread的子类(继承Thread),该类应重写Thread类的run方法。

步骤:

1.自定义一个类继承Thread.

2.复写Thread类中的run()方法.

3.创建线程对象,调用start()方法启动线程。

//自定义一个类继承Thread

写个小demo:

 1 class Demo extends Thread{
 2
 3          //复写Thread类中run()方法
 4
 5          public void run(){
 6
 7                    for (int x=0;x<60;x++) {
 8
 9                             System.out.println("demo run"+x);
10
11                    }
12
13          }
14
15 }
16
17
18
19 class ThreadDemo{
20
21          public static void main(String[] args) {
22
23                    //创建对象调用方法
24
25                    //创建自定义的线程对象实际上就是创建了线程
26
27                    Demo d = new Demo();
28
29                    //调用start()方法,启动线程;jvm调用线程对象的run()方法,执行内部代码
30
31                    d.start();
32
33                    for (int x=0;x<60;x++) {
34
35                             System.out.println("hello world!"+x);
36
37                    }
38
39          }
40
41 }

执行结果:

大家会看到执行的结果是交替进行的,并且还是不规则的交替打印。其原理是这样的:

上图解释了,两个线程同时进行,那么不规则如何解释呢?

也就是说:

因为多个线程都在获取cpu的执行权,cpu执行到谁,谁就运行。明确一点,在某一个时刻,只能有一个程序在运行。(多核除外)cpu在做着快速的切换,以达到看上去是同时运行的效果。我们可以形象的吧多线程的运行形容为在互相抢夺cpu的执行权。

这就是多线程的一个特性:随机性。

谁抢到谁执行,至于执行多长时间,cpu说的算。

接下来思考:我们为什么要复写这个run()方法呢?

Thread类用于描述线程。该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run()方法。

解释:

既然是用于描述线程,Thread类里面就会有很多功能用于操作线程。我们创建线程的目的其实是为了让线程执行一些代码,那么线程就需要在描述过程中定义这些代码存放的位置。线程要启动,要运行,要运行什么,这个什么在哪啊?线程提供了一个存储空间。这个空间就是run()方法。

也就是说,Thread类中的run()方法,用于存储线程要运行的代码。同理,主线程要运行的代码,放在main()方法中,这个是jvm定义的。

这是从run()方法本身说,那么从start()方法说,就是:

我们在主线程main()方法中创建Thread类对象,也就是创建了一个线程,这个线程对象通过调用start()方法,将线程启动。而这个start()方法又会调用Thread类中的run()来运行里面的的代码,如果我们不复写run(),直接创建线程对象,直接start(),我们不会得到我们想要的结果,因为父类Thread类中的run()方法中可能什么也没有写,start()方法调用run()也是白调用。所以,我们需要复写run()方法,里面写上我们自定义的代码,这样,run()方法才有意义。我们自定义的线程类继承了Thread类,调用start()方法,而start()方法会调用run()父类方法,因为我们复写了父类中的方法,父类会找子类,所以实际会调用我们写的run(0方法,这样我们自定义的代码才会运行。

因此,复写Thread类中的run()方法

目的:将自定义代码存储在run()方法中,让线程运行。

注意:在主线程中线程对象.start()方法和主线程中线程对象直接.run()方法的区别(面试)

d.start();//开启线程并执行该线程的run()方法

//d.run();仅仅是对象调用方法,在主线程中执行,而线程创建了,并没有运行。即还是单线程程序。

小练习:

创建两个线程,和主线程交替运行。

 1 class Test extends Thread{
 2
 3                                                                                                                                                            private String name;
 4
 5                                                                                                                                                                    Test(String name){
 6
 7                                                                                                                                                                this.name = name;
 8
 9                                                                                                                                                            }
10
11                                                                                                                                                            public void run(){
12
13                                                                                                                                                                for (int x=0;x<60;x++) {
14
15                                                                                                                                                                         System.out.println(name + "test....run"+x);
16
17                                                                                                                                                                }
18
19                                                                                                                                                            }
20
21 }
22
23
24
25 class ThreadDemo{
26
27                                                                                                                                                            public static void main(String[] args) {
28
29                                                                                                                                                                //创建对象调用方法
30
31                                                                                                                                                                //创建自定义的线程对象实际上就是创建了线程
32
33                                                                                                                                                                Demo d = new Demo();
34
35                                                                                                                                                                //调用start()方法,启动线程;jvm调用线程对象的run()方法,执行内部代码
36
37                                                                                                                                                                //d.start();//开启线程并执行该线程的run()方法
38
39                                                                                                                                                                //d.run();仅仅是对象调用方法,在主线程中执行,而线程创建了,并没有运行。即还是单线程程序。
40
41                                                                                                                                                                //测试小练习
42
43                                                                                                                                                                Test t1 = new Test("one");
44
45                                                                                                                                                                Test t2 = new Test("two");
46
47                                                                                                                                                                t1.start();
48
49                                                                                                                                                                t2.start();
50
51                                                                                                                                                                for (int x=0;x<60;x++) {
52
53                                                                                                                                                                        System.out.println("hello world!"+x);
54
55                                                                                                                                                                }
56
57                                                                                                                                                            }
58
59 }                                                                                                                                                             

线程运行状态(线程的生命周期)

线程在运行过程中,有几种状态是咱们必须掌握的。只有掌握这几种状态,我们才知道线程是怎样运作的。

获取线程对象以及名称

线程也有自己的名称,怎么获取呢?

找线程对象的方法吧。线程名称应该是定义在线程这类事物中。所以怎样获取这名称,是不是线程最熟悉?

Void setName(String name)

String getName()

线程都有自己默认的名称:Thread-编号,该编号从0开始。

 1 class Test extends Thread{
 2
 3                                                                                                                                                            private String name;
 4
 5                                                                                                                                                            Test(String name){
 6
 7                                                                                                                                                                this.name = name;
 8
 9                                                                                                                                                            }
10
11                                                                                                                                                            public void run(){
12
13                                                                                                                                                                for (int x=0;x<60;x++) {
14
15                                                                                                                                                                        System.out.println(this.getName() + "test....run"+x);
16
17                                                                                                                                                                }
18
19                                                                                                                                                            }
20
21 }
22
23
24
25 class ThreadDemo{
26
27                                                                                                                                                            public static void main(String[] args) {
28
29                                                                                                                                                                //创建对象调用方法
30
31                                                                                                                                                                //创建自定义的线程对象实际上就是创建了线程
32
33                                                                                                                                                                Demo d = new Demo();
34
35                                                                                                                                                                //调用start()方法,启动线程;jvm调用线程对象的run()方法,执行内部代码
36
37                                                                                                                                                                //d.start();//开启线程并执行该线程的run()方法
38
39                                                                                                                                                                //d.run();仅仅是对象调用方法,在主线程中执行,而线程创建了,并没有运行。即还是单线程程序。
40
41                                                                                                                                                                //测试小练习
42
43                                                                                                                                                                Test t1 = new Test("one");
44
45                                                                                                                                                                Test t2 = new Test("two");
46
47                                                                                                                                                                t1.start();
48
49                                                                                                                                                                t2.start();
50
51                                                                                                                                                                for (int x=0;x<60;x++) {
52
53                                                                                                                                                                        System.out.println("hello world!"+x);
54
55                                                                                                                                                                }
56
57                                                                                                                                                            }
58
59 }
 1 class Test extends Thread{
 2
 3                                                                                                                                                            //private String name;
 4
 5                                                                                                                                                            Test(String name){
 6
 7                                                                                                                                                                //this.name = name;
 8 super(name);
 9                                                                                                                                                            }
10
11                                                                                                                                                            public void run(){
12
13                                                                                                                                                                for (int x=0;x<60;x++) {
14
15                                                                                                                                                                        System.out.println(this.getName() + "test....run"+x);
16
17                                                                                                                                                                }
18
19                                                                                                                                                            }
20
21 }
22
23
24
25 class ThreadDemo{
26
27                                                                                                                                                            public static void main(String[] args) {
28
29                                                                                                                                                                //创建对象调用方法
30
31                                                                                                                                                                //创建自定义的线程对象实际上就是创建了线程
32
33                                                                                                                                                                Demo d = new Demo();
34
35                                                                                                                                                                //调用start()方法,启动线程;jvm调用线程对象的run()方法,执行内部代码
36
37                                                                                                                                                                //d.start();//开启线程并执行该线程的run()方法
38
39                                                                                                                                                                //d.run();仅仅是对象调用方法,在主线程中执行,而线程创建了,并没有运行。即还是单线程程序。
40
41                                                                                                                                                                //测试小练习
42
43                                                                                                                                                                Test t1 = new Test("one");
44
45                                                                                                                                                                Test t2 = new Test("two");
46
47                                                                                                                                                                t1.start();
48
49                                                                                                                                                                t2.start();
50
51                                                                                                                                                                for (int x=0;x<60;x++) {
52
53                                                                                                                                                                        System.out.println("hello world!"+x);
54
55                                                                                                                                                                }
56
57                                                                                                                                                            }
58
59 }

这里博主本来有两个疑惑来着,后来经过博主苦思冥想,终于破解:

1.第一个既然打印的this.getName(),为什么获取到的不是one,two?

2.都已经super(name);了,为什么获取到的还是new对象时的name?

回答:

1.this是代表本类对象的引用,这个大家都知道,所以this.getName()是在本类中调用getName()方法,本类有吗?没有。那么他就会去父类Thread类中找,父类有吗?有,获取的是什么呢?由于我们没有创建父类的对象,更没有创建父类创建线程名称的构造函数,更没有调用父类setName()的方法,所以,父类的getName()方法,返回的是默认的setName()方法的值,也就是Thread-编号。

2.super(name)是在构造方法里,调用的是父类的构造方法,而父类的该方法又被子类对象复写,所以,又会去找子类,所以相当于饶了父类这一个弯子。

其实在1中也还有个小疑问没有解开,就是当set(),get()方法组合与构造函数同时操作同一事物时,哪一个会好使。

Thread类中还有个静态方法:

Static Thread currentThread()   返回对当前正在执行的线程对象。

也可以获取当前线程的名称,而且比this更通用。

总结一下:

获取线程名称:

Static Thread currentThread():获取当前的线程对象

getName()

设置线程名称

setName()或者构造函数。

小案例:

需求:简单的卖票程序,多个窗口同时卖票。

代码如下:

 1 class Ticket extends Thread{
 2
 3                                                                                                                                                            private int tick = 100;
 4
 5                                                                                                                                                            public void run(){
 6
 7                                                                                                                                                                while(true){
 8
 9                                                                                                                                                                         if(tick>0){
10
11                                                                                                                                                                         System.out.println("sale:" + tick--);
12
13                                                                                                                                                                         }
14
15                                                                                                                                                                }
16
17                                                                                                                                                            }
18
19 }
20
21 class TicketDemo{
22
23                                                                                                                                                            public static void main(String[] args){
24
25                                                                                                                                                                Ticket t1 = new Ticket();
26
27                                                                                                                                                                Ticket t2 = new Ticket();
28
29                                                                                                                                                                Ticket t3 = new Ticket();
30
31                                                                                                                                                                Ticket t4 = new Ticket();
32
33                                                                                                                                                                t1.start();
34
35                                                                                                                                                                t2.start();
36
37                                                                                                                                                                t3.start();
38
39                                                                                                                                                                t4.start();
40
41                                                                                                                                                            }
42
43 }

但结果我们发现,每一个线程都会从100打印到1,也就是说每一个线程都卖了100张票,怎么解决呢?

让四个线程共享这100张票就可以了。

既然是共享的,没有特有的数据参与运算,我们就可以把100设为静态就搞定了。

但我们一般不这样,因为设为static后,它的生命周期过长。于是,我们就只创建一个对象,让它执行四次start()方法,结果发现也是可行的,只不过报了一个异常:

Java.lang.IllegalThreadStateExceptionThread-0…sale:99

这是无效的线程状态异常。已经运行的程序是不需要在开启的。那么显然,第一种创建方式,已经不行了,接下来我们来介绍一下第二种创建线程的方法。

创建线程的另外一种方法是声明实现Runnable接口的类。然后实现run方法。然后可以创建该类的实例,在创建时,作为一个参数来传递并启动。

Runnable接口里只有一个run()方法。

Thread类有一个构造方法可以接受Runnable接口类型的对象。

 1 class Ticket implements Runnable{//extends Thread{
 2
 3                                                                                                                                                            private int tick = 100;
 4
 5                                                                                                                                                            public void run(){
 6
 7                                                                                                                                                                while(true){
 8
 9                                                                                                                                                                         if(tick>0){
10
11                                                                                                                                                                         System.out.println("sale:" + tick--);
12
13                                                                                                                                                                         }
14
15                                                                                                                                                                }
16
17                                                                                                                                                            }
18
19 }
20
21 class TicketDemo{
22
23                                                                                                                                                            public static void main(String[] args){
24
25                                                                                                                                                                // Ticket t1 = new Ticket();
26
27                                                                                                                                                                // Ticket t2 = new Ticket();
28
29                                                                                                                                                                // Ticket t3 = new Ticket();
30
31                                                                                                                                                                // Ticket t4 = new Ticket();
32
33                                                                                                                                                                // t1.start();
34
35                                                                                                                                                                // t2.start();
36
37                                                                                                                                                                // t3.start();
38
39                                                                                                                                                                // t4.start();
40
41                                                                                                                                                                Ticket t = new Ticket();//
42
43                                                                                                                                                                //记住,开启线程的只能是Thread类或者Thread类子类的对象
44
45                                                                                                                                                                Thread t1 = new Thread(t);//
46
47                                                                                                                                                                Thread t2 = new Thread(t);
48
49                                                                                                                                                                Thread t3 = new Thread(t);
50
51                                                                                                                                                                Thread t4 = new Thread(t);
52
53                                                                                                                                                                t1.start();
54
55                                                                                                                                                                t2.start();
56
57                                                                                                                                                                t3.start();
58
59                                                                                                                                                                t4.start();
60
61
62
63                                                                                                                                                            }
64
65 }

创建线程的第二种方法,实现Runable接口

步骤:

1.定义类实现Runnable接口

2.覆盖Runnable接口中的run()方法

3通过Thread类建立线程对象

4将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数

5调用Thread类的start方法开启线程(让其调用Runnable接口子类的run()方法)。

其中复写Runnable接口中的run()方法我们前文已经分析过了,将线程要运行的代码存放在该run()方法中。

那么,为什么要将Runnable接口的子类对象传递给Thread的构造函数?

因为,自定义的run()方法所属的对象是Runnable接口的子类对象,所以要让线程去执行指定对象的run()方法。就必须明确该run()所属对象。

那么,创建线程的第二种实现方式和第一种继承方式有什么区别呢?(面试)

实现方式好处:避免了单继承的局限性。

在定义线程时,建议使用实现方式。

继承Thread线程代码存放在Thread子类run()方法中

实现Runnable,线程代码存放在接口的子类的run()方法中。

时间: 2024-10-10 04:44:58

Java中多线程的学习和使用(一)概述及创建方式的相关文章

java中多线程的实例代码

今天开始学习java中的多线程,在看书的过程中写了一个实例来练习多线程的用法,下面把代码放到博文里,里面很多的注释,可以帮助理解.     运行结果如下: main:启动MessageLoop线程...main:等待MessageLoop线程结束...main:继续等待.main:继续等待.main:继续等待.main:继续等待.Thread-0:消息1main:继续等待.main:继续等待.main:继续等待.main:继续等待.Thread-0:消息2main:继续等待.main:继续等待.

java中多线程模拟(多生产,多消费,Lock实现同步锁,替代synchronized同步代码块)

import java.util.concurrent.locks.*; class DuckMsg{ int size;//烤鸭的大小 String id;//烤鸭的厂家和标号 DuckMsg(){ } DuckMsg(int size, String id){ this.size=size; this.id=id; } public String toString(){ return id + " 大小为:" + size; } } class Duck{ private int

Java 中多线程

很多核心Java面试题来源于多线程(Multi-Threading)和集合框架(Collections Framework),理解核心线程概念时,娴熟的实际经验是必需的.这篇文章收集了 Java 线程方面一些典型的问题,这些问题经常被高级工程师所问到. 0.Java 中多线程同步是什么? 在多线程程序下,同步能控制对共享资源的访问.如果没有同步,当一个 Java 线程在修改一个共享变量时,另外一个线程正在使用或者更新同一个变量,这样容易导致程序出现错误的结果. 1.解释实现多线程的几种方法? 一

java中多线程通信实例:生产者消费者模式

线程间的通信: 其实就是多个线程再操作同一个资源,但是操作的动作不同   当某个线程进入synchronized块后,共享数据的状态不一定满足该线程的需要,需要其他线程改变共享数据的状态后才能运行,而由于当时线程对共享资源时独占的,它必须解除对共享资源的锁定的状态,通知其他线程可以使用该共享资源. Java中的 wait(),notify(),notifyAll()可以实现线程间的通信. 生产者--消费者问题是典型的线程同步和通信问题 /** * 生产者和消费者问题,生产者生成出产品,消费者去购

java中多线程执行时,为何调用的是start()方法而不是run()方法

Thead类中start()方法和run()方法的区别 1,start()用来启动一个线程,当调用start()方法时,系统才会开启一个线程,通过Thead类中start()方法来启动的线程处于就绪状态(可运行状态),此时并没有运行,一旦得到CPU时间片,就自动开始执行run()方法.此时不需要等待run()方法执行完也可以继续执行下面的代码,所以也由此看出run()方法并没有实现多线程. 2,run()方法是在本线程里的,只是线程里的一个函数,而不是多线程的.如果直接调用run(),其实就相当

黑马程序员------Java中多线程学习总结(一)

Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! 一.多线程的概念 进程:是一种“自包容”的运行程序,有自己的地址空间. 基于进程的特点是允许计算机同时运行两个或更多的程序 线程:是进程内部单一的一个顺序控制流 . 基于线程的多任务处理环境中,线程是最小的处理单位. 在Java中,一个应用程序可以包含多个线程.每个线程执行特定的任务,并可与其他线程并发执行.多线程使系统的空转时间减少,提高了CPU的利用率.多线程编程隐藏了CPU在任务之间切换的事实. 二.创建

Java中多线程的回顾---学习笔记(二)

线程的创建方式有两种: implements Runnable和extends Thread. 继承Thread类: package com.test.threadtest; import android.os.Bundle; import android.app.Activity; import android.view.Menu; public class MainActivity extends Activity { @Override protected void onCreate(Bu

Java中String类学习总结

java中String类的使用频率非常高,本人在学习此模块时,认为下列几点知识值得注意: 一.String是不可变对象 java.lang.String类使用了final修饰,不能被继承.Java程序中的所有字面值,即双引号括起的字符串,如"abc",都是作为String类的实例实现的.String是常量,其对象一旦构造就不能再被改变.换句话说,String对象是不可变的,每一个看起来会修改String值的方法,实际上都是创造了一个全新的String对象,以包含修改后的字符串内容.而最

Java中多线程技术

***********************************************声明****************************************************** 原创作品,出自 "晓风残月xj" 博客,欢迎转载,转载时请务必注明出处(http://blog.csdn.net/xiaofengcanyuexj). 由于各种原因,可能存在诸多不足,欢迎斧正! *******************************************