总 结
一、线程和进行:
1进程的概念
①进程就是正在执行的程序,一个进程通常就是一个正在执行的应用程序。从Windows角度讲,进程是含有内存和资源并安置线程的地方。
②准确的讲,进程就是一个可执行的程序一次运行的过程,它是系统进行资源分配和调度的一个独立单位。
2.线程的概念
线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数。
3.进程和线程的联系与区别
①一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个主线程。
②系统资源分配给进程,同一进程的所有线程共享该进程的所有资源。
③线程是指进程内的一个执行单元,也是进程内的可调度实体。
4多线程的概念
多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。
5多线程的好处
①Java支持编写多线程的程序;
②多线程最大好处在于可以同时并发执行多个任务;
③多线程可以最大限度地减低CPU的闲置时间,从而提高CPU的利用率。
6多线程的不利方面
①线程也是程序,所以线程需要占用内存,线程越多占用内存也越多;
②多线程需要协调和管理,所以需要CPU时间跟踪线程;
③线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题;
④线程太多会导致控制太复杂,最终可能造成很多Bug。
7 JAVA中主线程
①任何一个Java程序启动时,一个线程立刻运行,它执行main方法,这个线程称为程序的主线程;
也就是说,任何Java程序都至少有一个线程,即主线程;
②主线程的特殊之处在于:
③它是产生其它线程子线程的线程;
④通常它必须最后结束,因为它要执行其它子线程的关闭工作。
二、Java创建线程的两种方法
继承Thread类的方式
实现Runnable接口的方式
1在Java中要实现线程,最简单的方式就是扩展Thread类,重写其中的run方法,方法原型如下:
public void run()
Thread类中的run方法本身并不执行任何操作,如果我们重写了run方法,当线程启动时,它将执行run方法。
Thread类也实现了Runnable接口。
①通过继承Thread类
定义:
public class MyThread extends Thread {
public void run() {
……
}
}
调用:
MyThread thread = new MyThread();
thread.start();
②自定义线程 – 实现Runnable接口
java.lang.Runnable接口中仅仅只有一个抽象方法:
public void run()
也可以通过实现Runnable接口的方式来实现线程,只需要实现其中的run方法即可;
Runnable接口的存在主要是为了解决Java中不允许多继承的问题。
③通过实现Runnable接口
定义:
public class MyThread implements Runnable{
@Override
public void run() {
……
}
}
调用:
MyThread r = new MyThread();
//创建一个线程作为外壳,将r包起来,
Thread thread = new Thread(r);
thread.start();
三、使用匿名内部类创建线程
1匿名内部类的概念
①内部类是指在一个外部类的内部再定义一个类。
②匿名内部类也就是没有名字的内部类。
③正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写。
④使用匿名内部类的前提条件是必须继承一个父类或实现一个接口。
2使用匿名内部类的注意点
①继承抽象类的匿名内部类
abstract class Person {
public abstract void eat();
}
public class Demo {
public static void main(String[] args) {
Person p = new Person() {
public void eat() {
System.out.println("eat something");
}
};
p.eat();
}
}
②实现接口的匿名内部类
interface Person {
public void eat();
}
public class Demo {
public static void main(String[] args) {
Person p = new Person() {
public void eat() {
System.out.println("eat something");
}
};
p.eat();
}
}
③匿名内部类不能有构造方法;
④匿名内部类不能定义任何静态成员、方法和类;
⑤匿名内部类不能是public、protected、private、static;
⑥只能创建匿名内部类的一个实例;
⑦一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类;
⑧因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效;
⑨在匿名类中用this时,这个this指的是匿名类本身。如果我们要使用外部类的方法和变量的话,应该加上外部类的类名。
3使用匿名内部类创建线程
①匿名内部类常用在多线程的实现上,因为要实现多线程必须继承Thread类或是实现Runnable接口。
Thread类的匿名内部类实现
public class ThreadDemo {
public static void main(String[] args) {
Thread thread = new Thread() {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.print(i + " ");
}
}
};
thread.start();
}
}
等价的非匿名内部类实现
class MyThread extends Thread {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.print(i + " ");
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
}
}
Runnable接口的匿名内部类实现
public class RunnableDemo {
public static void main(String[] args) {
Runnable r = new Runnable() {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.print(i + " ");
}
}
};
Thread thread = new Thread(r);
thread.start();
}
}
等价的非匿名内部类实现
class MyThread implements Runnable {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.print(i + " ");
}
}
}
public class RunnableDemo {
public static void main(String[] args) {
MyThread r = new MyThread();
Thread thread = new Thread(r);
thread.start();
}
}
四、Thread类中常用方法
1 Thread类的常用静态方法
方 法 原 型 |
说 明 |
static Thread currentThread() |
返回对当前正在执行的线程对象的引用 |
static void sleep(long millis) throws InterruptedException |
让当前正在执行的线程休眠(暂停执行),休眠时间由millis(毫秒)指定 |
static void sleep(long millis, int nanos) throws InterruptedException |
让当前正在执行的线程休眠,休眠时间由millis(毫秒)和nanos(纳秒)指定 |
static void yield() |
暂停当前正在执行的线程,转而执行其它的线程 |
static boolean interrupted() |
判断当前线程是否已经中断 |
java.lang.Thread类用于创建和操作线程,其中包括几个很重要的静态方法,用于控制当前线程:
2 Thread类的构造方法
构 造 方 法 |
说 明 |
Thread() |
创建一个新的线程 |
Thread(String name) |
创建一个指定名称的线程 |
Thread(Runnable target) |
利用Runnable对象创建一个线程,启动时将执行该对象的run方法 |
Thread(Runnable target, String name) |
利用Runnable对象创建一个线程,并指定该线程的名称 |
Thread类共提供8种构造方法重载,以下是常用的几种:
3线程优先级
①事实上,计算机只有一个CPU,各个线程轮流获得CPU的使用权,才能执行任务;
②优先级较高的线程有更多获得CPU的机会,反之亦然;
③优先级用整数表示,取值范围是1~10,一般情况下,线程的默认优先级都是5,④但是也可以通过setPriority和getPriority方法来设置或返回优先级;
⑤Thread类有如下3个静态常量来表示优先级
MAX_PRIORITY:取值为10,表示最高优先级。
MIN_PRIORITY:取值为1,表示最底优先级。
NORM_PRIORITY:取值为5,表示默认的优先级。
4 sleep用法
①Thread.sleep(long millis)和Thread.sleep(long millis, int nanos)静态方法强制当前正在执行的线程休眠(暂停执行),以“减慢线程”。当线程睡眠时,它入睡在某个地方,在苏醒之前不会返回到可运行状态。当睡眠时间到期,则返回到可运行状态。
②线程睡眠的原因:线程执行太快,或者需要强制进入下一轮睡眠的实现:调用静态方法。
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
5 睡眠的位置:
①为了让其他线程有机会执行,可以将Thread.sleep()的调用放线程run()之内。这样才能保证该线程执行过程中会睡眠。
②线程睡眠是帮助所有线程获得运行机会的最好方法。
③线程睡眠到期自动苏醒,并返回到可运行状态,不是运行状态。sleep()中指定的时间是线程不会运行的最短时间。因此,sleep()方法不能保证该线程睡眠到期后就开始执行。
④sleep()是静态方法,只能控制当前正在运行的线程。
6 yield的用法
①Thread.yield()方法作用是:暂停当前正在执行的线程对象,并执行其他线程,让相同优先级的线程之间能适当的轮转执行。
②yield() 做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。
③结论:yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果。
7 join的用法
①常用于主线程需要用到子线程执行完后的结果,即主线程需要等待子线程执行完成后再结束。
例:创建并启动线程t,加入到当前运行的线程中
MyThread t = new MyThread();
t.start();
t.join();
方 法 原 型 |
说 明 |
|
final void setDaemon(boolean on) |
将该线程设置为后台线程 |
|
final boolean isDaemon() |
判断该线程是否为后台线程 |
8与后台线程相关的方法
要将某个线程设置为后台线程的话,必须在它启动之前调用setDeamon方法;
默认情况下,由前台线程创建的线程仍是前台线程,由后台线程创建的线程仍是后台线程。