一、线程和进程的概念
进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。
线程是指进程中的一个执行流程,一个进程中可以运行多个线程。比如java.exe进程中可以运行很多线程。线程总是属于某个进程,进程中的多个线程共享进程的内存。
“同时”执行是人的感觉,在线程之间实际上轮换执行。
二、线程的两种实现方式
在java中有两种方式可以实现多线程操作:1、继承Thread类 2、实现Runnable接口。
- 继承Thread类
public
class
Test {
public
static
void
main(String[] args) {
MyThread myThread1 =
new
MyThread();
MyThread myThread
2
=
new
MyThread();
myThread1.start();
myThread
2
.start();
}
}
class
MyThread
extends
Thread {
@Override
public
void
run() {
for
(
int
i = 0; i < 10; i++) {
System.
out
.println(
"myThread
运行了第 "
+ i +
"
次"
);
}
}
}
关于为什么调用线程的start()方法,而不直接调用run()方法:
直接调用run()方法的话,两个线程会顺序执行,也就是说两个线程根本没有进行cup资源的强占。
调用start()方法,虽然start()方法内部还是会调用run()方法,但start()方法内部某些操作能让两个线程等待cpu的调度,从而两个线程会交互执行。
操作系统有很多种:Windows、Linux、UNIX等,既然多线程操作中要进行CPU资源的强占,也就是等待CPU的调度,那么这些调度的操作是由各个操作系统的底层实现的,所以在java程序中根本就没有实现的方法,那么此时java的设计者定义了native关键字(下面代码中的start0),使用此关键字表示可以调用操作系统的底层函数,那么这样的技术又称为JNI技术(java Native Interface)。
Start()的内部调用:
|
public synchronized void start() {
if (threadStatus != 0 || this != me)
throw new IllegalThreadStateException();
group.add(this);
start0();
if (stopBeforeStart) {
stop0(throwableFromStop);
}
}
private native void start0();
|
- 实现Runnable接口
在实际开发中一个多线程的操作类很少去使用Thread类完成,而是通过Runnable接口完成。
public
class
Test {
public
static
void
main(String[] args) {
MyRunnable myRunnable1 =
new
MyRunnable();
new
Thread(myRunnable1).start();
}
}
class
MyRunnable
implements
Runnable {
@Override
public
void
run() {
for
(
int
i = 0; i < 10; i++) {
System.
out
.println(
"myThread
运行了第 "
+ i +
"
次"
);
}
}
}
- Thread和Runnable的区别
在实际开发中要是多线程则肯定永远以实现Runnable接口为正统操作,因为实现Runnable接口相比继承Thread类有如下好处:
- 避免单继承的局限,一个类可以同时实现多个接口。
- 适合资源共享(重要)
以买票的程序为例:
通过Thread类完成:
public
class
Test {
public
static
void
main(String[] args) {
MyThread myThread1 =
new
MyThread();
MyThread myThread2 =
new
MyThread();
MyThread myThread3 =
new
MyThread();
myThread1.setName(
"1
号窗口:"
);
myThread2.setName(
"2
号窗口:"
);
myThread3.setName(
"3
号窗口:"
);
myThread1.start();
myThread2.start();
myThread3.start();
}
}
class
MyThread
extends
Thread {
private
int
ticket
= 5;
@Override
public
void
run() {
for
(
int
i = 0; i < 5; i++) {
if
(
this
.
ticket
<= 0) {
return
;
}
System.
out
.println(Thread.
currentThread
().getName() +
"
卖出1张票,目前剩余 "
+ --
ticket
+
"
张票"
);
try
{
Thread.
sleep
(1000);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
}
结果:
1号窗口:卖出1张票,目前剩余 4 张票
2号窗口:卖出1张票,目前剩余 4 张票
3号窗口:卖出1张票,目前剩余 4 张票
1号窗口:卖出1张票,目前剩余 3 张票
2号窗口:卖出1张票,目前剩余 3 张票
3号窗口:卖出1张票,目前剩余 3 张票
1号窗口:卖出1张票,目前剩余 2 张票
2号窗口:卖出1张票,目前剩余 2 张票
3号窗口:卖出1张票,目前剩余 2 张票
1号窗口:卖出1张票,目前剩余 1 张票
2号窗口:卖出1张票,目前剩余 1 张票
3号窗口:卖出1张票,目前剩余 1 张票
1号窗口:卖出1张票,目前剩余 0 张票
2号窗口:卖出1张票,目前剩余 0 张票
3号窗口:卖出1张票,目前剩余 0 张票
总共5张票,可Thread却卖出了15张,因为每一个线程都卖自己的票,没有资源共享。
通过Runnable完成:
public
class
Test {
public
static
void
main(String[] args) {
MyRunnable myRunnable1 =
new
MyRunnable();
new
Thread(myRunnable1,
"1
号窗口:"
).start();
new
Thread(myRunnable1,
"2
号窗口:"
).start();
new
Thread(myRunnable1,
"3
号窗口:"
).start();
}
}
class
MyRunnable
implements
Runnable {
private
int
ticket
= 5;
@Override
public
void
run() {
for
(
int
i = 0; i < 5; i++) {
if
(
this
.
ticket
<= 0) {
return
;
}
System.
out
.println(Thread.
currentThread
().getName() +
"
卖出1张票,目前剩余 "
+ --
ticket
+
"
张票"
);
try
{
Thread.
sleep
(1000);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
}
结果:
2号窗口:卖出1张票,目前剩余 4 张票
1号窗口:卖出1张票,目前剩余 3 张票
3号窗口:卖出1张票,目前剩余 2 张票
2号窗口:卖出1张票,目前剩余 1 张票
1号窗口:卖出1张票,目前剩余 0 张票