进程是系统进行资源分配和调度的基本单位。而线程是程序运行的最小单位。
一个进程里面会有多个线程共享进程的资源,而这又会导致一系列的数据安全和一致性问题,就需要我们认真去学习并发体系的相关知识去保证临界区资源的安全性。
java实现了这样一个类,名叫Thread,是java的线程对象
进入到Thread源码中可以看到源码提供了两种创建多线程的方式
方式一:继承Thread类class PrimeThread extends Thread {
long minPrime;
PrimeThread(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
PrimeThread p = new PrimeThread(143);
p.start();
方式二:继承Runnable接口
class PrimeRun implements Runnable {
long minPrime;
PrimeRun(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
将我们要运行的代码写到run()方法里面,这样新建的线程就会执行run()函数体里面的代码
使用继承Thread类实现的话,缺陷就在于java的单继承限制,而实现Runnable接口之后我们可以继承其他的类来实现更多的功能,扩展性更好。
通过Thread源码可以看到,有多种构造方法
其中一个,参数为实现了Runnable接口的实例
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
我们可以看到,我们只需要传递一个实现了Runnable接口的实例,就可以实现多线程。因此我随便找了一个实现了Runnable接口的类来实验验证。证实确实可以。
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
for(int i=1;i<=20;i++){
System.out.printf("I am TimerTask-1:%dn",i);
}
}
};
Thread threadThree = new Thread(timerTask);
threadThree.start();
我们进一步查看Thread的源码,发现有这样的字段
private Runnable target;
在上面的那个构造函数中又会调用init()方法,而init()方法中又会有如下的代码,将我们传入的实例赋给Thread.target
this.target = target
而Thread 源码中重写了这个run()方法
@Override
public void run() {
if (target != null) {
target.run();
}
}
所以说Thread.run()方法实际上还是使用的我们传入的实现了Runnable接口的实例的run()方法
在《并发编程之美中》,作者还向我们推荐了FutureTask,可以在任务执行完毕后返回一个结果。
实验代码:import java.util.TimerTask;
public class ThreadTest {
public static class MyThread extends Thread{
@Override
public void run(){
for(int i=1;i<=20;i++){
System.out.printf("I am MyThread:%dn",i);
}
}
}
public static class RunnableTest implements Runnable{
@Override
public void run() {
for(int i=1;i<=20;i++){
System.out.printf("I am RunnableTest:%dn",i);
}
}
}
public static void main(String[] args){
MyThread thread = new MyThread();
thread.start();
RunnableTest runnableTest = new RunnableTest();
Thread threadTwo = new Thread(runnableTest);
threadTwo.start();
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
for(int i=1;i<=20;i++){
System.out.printf("I am TimerTask-1:%dn",i);
}
}
};
TimerTask timerTaskCopy = new TimerTask() {
@Override
public void run() {
for(int i=1;i<=20;i++){
System.out.printf("I am TimerTask-2:%dn",i);
}
}
};
Thread threadThree = new Thread(timerTask);
threadThree.start();
Thread threadFour = new Thread(timerTaskCopy);
threadFour.start();
}
}
实验结果如下,如果感觉不明显,可以增加i遍历的范围
文章内容来自对网络资料,书本的归纳整理和自己的实践,如果有理解错误或者不足的地方,还请不吝赐教。



