经常会有人问你,什么是进程,什么是线程,进程和线程有什么关系
(区别),所以我觉得还是有必要总结一下的,虽然可能不太好;
1.定义:所谓进程,就是正在进行的程序,每一个进程都有自己独立的一块
内存空间,比如在Windows系统下,一个EXE就是一个进程,可以在任务管理下
查看你运行的所有进程,而针对于此,线程指的是进程中的一个执行流程,
一个进程可以包含多个线程,多个线程共享一片内存空间;
2.线程实现的方式:
a) 继承Thread类,复写run方法(放置需要采用多线程技术的代码),建立对象
对象通过start启动多线程
ep1:
完整代码:
package com.ahuiby.test;
class Dog extends Thread{
public Dog(){}
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+": "+i);
}
}
}
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Dog d1=new Dog();
Dog d2=new Dog();
d1.start();
d2.start();
}
}
运行结果:
Thread-1: 0
Thread-1: 1
Thread-0: 0
Thread-0: 1
Thread-1: 2
Thread-0: 2
Thread-1: 3
Thread-0: 3
Thread-1: 4
Thread-0: 4
b) 继承Runnable,复写run方法(放置需要采用多线程技术的代码),建立对象,将对象作为Thread的参数创建Thread对象
通过start启动多线程
ep2:
完整代码:
package com.ahuiby.test;
class Dog implements Runnable{
public Dog(){}
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+": "+i);
}
}
}
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Dog d1=new Dog();
Thread th1=new Thread(d1);
Dog d2=new Dog();
Thread th2=new Thread(d2);
th1.start();
th2.start();
}
}
运行结果:
Thread-1: 0
Thread-0: 0
Thread-0: 1
Thread-0: 2
Thread-0: 3
Thread-0: 4
Thread-1: 1
Thread-1: 2
Thread-1: 3
Thread-1: 4
c) 继承Thread类和实现Runnable接口区别
①:Thread类不能对同一个对象多次启动线程,即这样产生的后果是不能够实现数据共享,但是可以
通过同步来解决,而Runnable可以对同一个对象进行多次线程启动,可以直接实现数据共享;这与
他们创建对象的方式有很大关系;
Thread创建对象的方式:
Dog d1=new Dog();
Dog d2=new Dog();
d1.start();
d2.start();
Runnable创建对象的方式:
Dog d1=new Dog();
Thread th1=new Thread(d1);
Thread th2=new Thread(d1);
th1.start();
th2.start();
②Java只支持单继承,如果继承了Thread类,该类不能再继承其他类,这限制了类的可扩展性,所以
在这一点上Runnable还是优于Thread的;
3.每次运行一个Java程序,至少运行了2个线程,一个是main线程,一个是垃圾收集线程
4.线程状态:创建、就绪、运行、阻塞、结束
a) 创建:新创建一个线程对象
b) 就绪:调用start()方法以后,如果CPU处于占用状态,该线程必须等待运行中的线程结束或挂起,此时
线程的状态被称为挂起;
c) 运行:当线程获得CPU的使用权之后,该状态被称为运行状态
d) 阻塞:线程因为各种原因而放弃对CPU的使用,暂时停止运行,此时线程所处的状态被称之为阻塞;
阻塞三种情况:
①:等待阻塞:运行中的线程调用wait()方法后,线程进入阻塞状态;
②:同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,线程进入阻塞状态;
③:其他阻塞:运行的线程执行sleep()或join()方法,或等待用户输入,线程进入阻塞状态;
e) 结束:线程执行完毕后的状态称之为结束(也叫dead);
5.线程调度的优先级别:
线程有优先级别,优先级别高的更有机会占有CPU;级别在1-10之间
MAX_PRIORITY:10
MIN_PRIORITY:1
NORMAL_PRIORITY:5
6.Thread类src中常用方法探索:
a) 类声明:public
class Thread implements Runnable 从这里
可以看出Thread类其实也是实现了Runnable接口;也就可以解释
为什么我们可以通过Runnable接口来实现多线程;
b) *(预读部分,仅作了解)
/* Make sure registerNatives is the first thing <clinit> does. */
private static native void registerNatives();
static {
registerNatives();
}
native:在Java中,用native修饰方法的,表示该方法并不是由Java去完成
而是由C/C++去完成,生成dll文件,由Java来调用;
registerNatives:这个方法由private修饰,并不会对象直接调用,它是由
紧跟着的static语句块中调用的;
c) 字段:
private char name[];//线程名
private int priority;//线程优先级别
private Runnable target;//即将运行的线程
public final static int MIN_PRIORITY = 1;//最小优先级
public final static int MAX_PRIORITY = 10;//最大优先级
public final static int NORMAL_PRIORITY = 5;//默认优先级
d) 方法:
//对线程名的操作
//设置线程名:checkAccess():检查线程名是否安全
public final void setName(String name) {
checkAccess();
this.name = name.toCharArray();
}
//获取线程名
public final String getName() {
return String.valueOf(name);
}
//对线程的优先级别的操作
//设置线程优先级别
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
if((g = getThreadGroup()) != null) {
if (newPriority > g.getMaxPriority()) {
newPriority = g.getMaxPriority();
}
setPriority0(priority = newPriority);
}
}
//获取线程的优先级别(final修饰的方法可以被重载,但是不能被覆盖)
public final int getPriority() {
return priority;
}
//覆盖run方法
@Override
public void run() {
if (target != null) {
target.run();
}
}
//start方法
public synchronized void start(){//具体代码}
start被同步锁了,如果其他线程要调用start方法,必须等待当前对象释放锁
//currentThread获得当前线程
public static native Thread currentThread();
//join方法
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}