一、进程
进程:是正在运行的程序
是系统进行资源分配和调用的独立单位
每一个进程都有它自己的内存空间和系统资源
二、线程
线程:是进程中的单个顺序控制流,是一条执行路径
单线程:一个进程如果只有一条执行路径,则称为单线程程序
多线程:一个进程如果有多条执行路径,则称为多线程程序。
三、多线程的实现方式
1、方式一:继承Thread类
public
class Thread implements Runnable {
定义一个类继承Thread类
在定义的类中重写run方法
创建定义的类的对象
启动线程
public static void main(String[] args) {
new Thread(new Thread() {
public void run() {
for(int i=0;i<50;i++){
System.out.println("a"+i);
}
}
}).start();
new Thread(new Thread() {
public void run() {
for(int i=0;i<50;i++){
System.out.println("b"+i);
}
}
}).start();
}
2、两个小问题:
为什么要重写run()方法?
因为run()是用来封装被线程指定的代码
run()方法和start()方法的区别?
run():封装线程执行的代码,直接调用,相当于普通方法的调用。
start():启动线程;然后由JVM调用此线程的run()方法
四、设置和获取线程名称:
1、Thread类中设置和获取线程名称的方法
//将此线程的名称更改为等于参数name
public final synchronized void setName(String name) {
checkAccess();
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
if (threadStatus != 0) {
setNativeName(name);
}
}
//返回此线程的名称
public final String getName() {
return name;
}
2、Thread如何命名的源代码
/**
构造方法里面的名字为Thread-
*/
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
//nextThreadNum方法给threadInitNumber++
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
//无参构造方法调用此init方法
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
//此name就是threadInitNumbe
this.name = name;
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */
/* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
}
/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
}
/* checkAccess regardless of whether or not threadgroup is
explicitly passed in. */
g.checkAccess();
/*
* Do we have the required permissions?
*/
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
g.addUnstarted();
this.group = g;
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext =
acc != null ? acc : AccessController.getContext();
this.target = target;
setPriority(priority);
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
tid = nextThreadID();
}
3、无参方法设置名字
public static void main(String[] args) {
//继承Thread方法,所以可以使用Thread方法里面的getName
new Thread(new Thread() {
public void run() {
setName("线程aaaa=====");
for(int i=0;i<50;i++){
System.out.println(getName()+":a:"+i);
}
}
}).start();
new Thread(new Thread() {
public void run() {
setName("线程bbbb=====");
for(int i=0;i<50;i++){
System.out.println(getName()+":b:"+i);
}
}
}).start();
}
4、代参构造方法设置名字
public static void main(String[] args) {
//继承Thread方法,所以可以使用Thread方法里面的getName
new Thread(new Thread("线程aaaa") {
public void run() {
for(int i=0;i<50;i++){
System.out.println(getName()+":a:"+i);
}
}
}).start();
new Thread(new Thread("线程bbbb") {
public void run() {
for(int i=0;i<50;i++){
System.out.println(getName()+":b:"+i);
}
}
}).start();
}
5、currentThread():返回对当前正在执行的线程对象的引用
public static native Thread currentThread();
如何拿到main方法的线程名字
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());
}
五、线程调度
1、线程有两种调度模型
分时调度模型:所有的线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间
抢占式调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的CPU时间片相对多一些。
2、java使用的是抢占式调度模型:
假如计算机只有一个CPU,那么CPU在某一个时刻只能执行一条指令,线程只有得到CPU时间片,也就是使用权,才可以执行指令。所以说多线程程序的执行是有随机性,因为谁抢到CPU的使用权是不一定的。
3、Thread类中设置和获取线程优先级的方法
//设置优先级
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);
}
}
//获取优先级
public final int getPriority() {
return priority;
}
线程默认优先级是5;
线程优先级的范围是1-10
线程优先级高仅仅表示线程获取的CPU时间片的几率较高
六、线程控制
Thread.java
//使当前正在执行的线程停留(暂停执行)指定的毫秒数
public static native void sleep(long millis) throws InterruptedException;
//等待这个线程死亡
public final void join() throws InterruptedException {
join(0);
}
//将此线程标记为守护线程,当运行的线程都是守护线程时,java虚拟机将退出
public final void setDaemon(boolean on) {
checkAccess();
if (isAlive()) {
throw new IllegalThreadStateException();
}
daemon = on;
}
public static void main(String[] args) {
//继承Thread方法,所以可以使用Thread方法里面的getName
Thread a= new Thread("线程aaaa"){
public void run() {
for(int i=0;i<50;i++){
try {
Thread.sleep(100); //休眠0.1s
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(getName()+":a:"+i);
}
}
};
a.start();
try {
a.join(); //等待a线程执行完毕,才能往下执行
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(new Thread("线程bbbb") {
public void run() {
for(int i=0;i<50;i++){
System.out.println(getName()+":b:"+i);
}
}
}).start();
}
只有守护线程时虚拟机并不是马上退出,而是等一段时间。
public static void main(String[] args) {
//继承Thread方法,所以可以使用Thread方法里面的getName
Thread a= new Thread("刘备"){
public void run() {
for(int i=0;i<10;i++){
try {
Thread.sleep(100); //休眠0.1s
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(getName()+":a:"+i);
}
}
};
a.start();
Thread b= new Thread("张飞"){
public void run() {
for(int i=0;i<50;i++){
try {
Thread.sleep(100); //休眠0.1s
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(getName()+":b:"+i);
}
}
};
b.setDaemon(true);//设置成守护线程
b.start();
Thread c= new Thread("关羽"){
public void run() {
for(int i=0;i<50;i++){
try {
Thread.sleep(100); //休眠0.1s
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(getName()+":c:"+i);
}
}
};
c.setDaemon(true);//设置成守护线程
c.start();
}
七、线程的生命周期
八、多线程的实现方式
1、方式二:实现Runnable接口
public interface Runnable {
public abstract void run();
}
定义一个类MyRunnable实现Runnable接口
在MyRunnable类中重写run()方法
创建MyRunnable类的对象
创建Thread类的对象,把MyRunnable对象作为构造方法的参数
启动线程
public static void main(String[] args) {
//如果继承Thread方法,所以可以使用Thread方法里面的getName
new Thread(new Runnable(){
public void run() {
for(int i=0;i<10;i++){
try {
Thread.sleep(100); //休眠0.1s
} catch (Exception e) {
e.printStackTrace();
}
// System.out.println(getName()+":a:"+i);//因为是Runnable所以没有getName方法
System.out.println(Thread.currentThread().getName()+":a:"+i);
}
}
}).start();
new Thread(new Runnable(){
public void run() {
for(int i=0;i<10;i++){
try {
Thread.sleep(100); //休眠0.1s
} catch (Exception e) {
e.printStackTrace();
}
// System.out.println(getName()+":a:"+i);//因为是Runnable所以没有getName方法
System.out.println(Thread.currentThread().getName()+":a:"+i);
}
}
},"第二个参数为线程的名字").start();
}
相比继承Thread类,实现Runnable接口的好处
避免了java单继承的局限性
适合多个相同程序的代码处理同一个资源的情况,把线程和程序的代码,数据有效分离,较好的体现了面向对象的设计思想