一、进程
进程:是正在运行的程序
是系统进行资源分配和调用的独立单位
每一个进程都有它自己的内存空间和系统资源
二、线程
线程:是进程中的单个顺序控制流,是一条执行路径
单线程:一个进程如果只有一条执行路径,则称为单线程程序
多线程:一个进程如果有多条执行路径,则称为多线程程序。
三、多线程的实现方式
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单继承的局限性
适合多个相同程序的代码处理同一个资源的情况,把线程和程序的代码,数据有效分离,较好的体现了面向对象的设计思想
 
                         
                                

