进程与线程
进程
是程序运行的基本单位,一个程序就是代表一个进程,进程与进程之间是相互独立的,它们是由 CPU 进行调度的(分配内存空间) ,由于它们是相互独立所以各自的资源不共享。一台电脑中可以运行多个程序,并且执行效率快,所以它是高效而且并发性的。在一个时间段中,可以执行多个进程(程序),一个进程是非常占内存空间的,对 CPU 的开销也是非常大的。
线程
是程序流中最小的执行单位,一个程序中至少存在一个线程,线程占空间内存是非常少的,一个进程中多个线程资源是可以共享的。线程消耗的内存少执行效率高,同一时间段中可以执行多个线程,线程具有并发性的特点。(线程调度:(分时间)轮询调度和抢占式调度),资源共享;注意的是资源是否会丢失(安全)。
区别
一个程序至少有一个进程,一个进程至少有一个线程
线程的划分尺度小于进程,使得多线程程序的并发性高。
进程有独立的内存单元,而多个线程共享内存
线程必须依靠存在于应用程序中
多线程实在程序中多个部分同时执行,但是系统并没有把多个线程当场多个独立的应用,来实现进程的调度和管理资源分配。
线程开销小,不利于资源的管理和保护,进程正好相反。
线程数据共享
线程的实现
java 中一共有两种方式实现线程
继承 Thread 类
通过继承 java.lang.Thread 类来实现线程:
1
2
3
4
5
6
7
8
9
10
11public class MyThread extends Thread{
public void run(){
.....
}
}
public static void main(String[] args){
MyThread mt = new MyThread();
mt.start();
}继承 Thread 类是之后要实现 run() 方法,线程启动之后是执行 run() 方法。之后调用 Thread 的 start 的方法就能开启线程( 同一对象不能调用同一 start() 方法)
实现 Runnable 接口,并且 start()
- 内部类实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27new Thread(new Runnable(){
public void run() {
int i=0;
i++;
System.out.println(i);
}
}).start();
```
2. 另写一个类实现接口
```java
class myRunnable implement Runnable{
public void run() {
int i=0;
i++;
System.out.println(i);
}
}
public static void main(String[] args){
myRunnable mr = new myRunnable();
Thread t1 = new Thread(mr);
t1.start();
}
- 内部类实现
生命周期
状态包括 出生状态,就绪状态,运行状态,等待状态,休眠状态,阻塞状态,死亡状态。
在用户 new 出来的时候为“出生状态”;此时当用户调用 start() 的时候处于“就绪状态”;当线程得到资源后进入“运行状态”;当运行时调用 wait() 方法时线程处于 “等待状态”,此时必须从其他线程调用 notify() 方法才能唤醒,notifyAll() 可以除了调用这个线程以外所有处于等待状态下的线程;当线程调用 sleep() 方法时会进入 “休眠状态”,结束后进入就绪;如果一个线程在运行状态下发出输入/输出(Sacnner)请求,该线程将进入阻塞状态,输入/输出结束时线程进入就绪 状态;当线程的 run() 方法执行完毕/异常/stop() 时线程进入“死亡状态”
线程常用方法
1. 线程的休眠( sleep )
静态方法,最后不要用 Thread 对象调用它,因为它睡眠的始终是当前正在运行的线程,不是调用它的线程对象,只对正在运行状态的线程对象有效。单位 ms 通常使得线程释放当前 cpu 执行权,苏醒后并不一定时运行状态,只能保证他进入就绪状态。
1 | try{ |
2. 线程的加入(join)
不是静态方法,作用是当前线程等待这个调用 join() 方法对象的线程结束在继续执行 join() 下一句代码。
1 | public static void main(String[] args) throws InterruptedException{ |
如例子,main 线程要等到 t1 线程运行结束之后,才会输入“main end”。如果没有 join 那么变成并行,“main end”可能会被提前打印出来。
没有实现让其他线程并发执行,线程是顺序执行的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public static void main(String[] args) throws InterruptedException
{
System.out.println("main start");
Thread t1 = new Thread(new Worker("thread-1"));
Thread t2 = new Thread(new Worker("thread-2"));
t1.start();
//等待t1结束,这时候t2线程并未启动
t1.join();
//t1结束后,启动t2线程
t2.start();
//等待t2结束
t2.join();
System.out.println("main end");
}让t1、t2线程并行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public class JoinTest
{
public static void main(String[] args) throws InterruptedException
{
System.out.println("main start");
Thread t1 = new Thread(new Worker("thread-1"));
Thread t2 = new Thread(new Worker("thread-2"));
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("main end");
}
}
3. 线程的让步 yield()
yield()方法它也可以让当前正在执行的线程暂停,让出cpu资源给其他的线程。但是和sleep()方法不同的是,它不会进入到阻塞状态,而是进入到就绪状态。yield()方法只是让当前线程暂停一下,重新进入就绪的线程池中,cpu 调度重新调度,可能出现这样的情况:当某个线程调用yield()方法之后,调度器又将其调度出来重新进入到运行状态执行。