多线程基础讲解

多线程:
1、 什么是程序、进程、线程?
程序:它是为了完成特定任务,使用某种语言编写的静态指令集合。
进程:它是程序的一次执行,或者是正在运行的程序。
进程的开始,进程的运行状态,进程的结束。是有一定的生命周期的。
如果一个程序被运行了多次在同一个电脑上面,则称该程序时多进程程序。例如:你可以在同一个电脑上面挂多个QQ。
由于进程是一个逻辑概念 (不是客观事物),所以它本身是不受CPU的调控和执行。但是它是可以接受对资源的分配控制的。
例如:创建一个班级,这个班级就是一个逻辑的概念,班级本身是不存在的,它是有班级中的学生构成的。但是我们对学习的管控是针对学生而言的,可以对班级的名称,大小进行安排,在计算机里即对资源进行限定。进程对计算机中的资源是共享使用的。
线程:是进程中受到CPU执行的指令集合,它是进程的里面的执行路径。结合上边的例子将线程可以理解为班级里面进行学习的各个学习小组。
一个进程中至少要有一个线程,否则进程是不会执行的。在Java语言中,main函数执行的时候可看为主线程,类中的函数在执行的时候可看为子进程。
进程:是动态的 ,进程是由线程构成的。进程只是对内存资源和CPU资源的逻辑概括。线程它不是独立使用内存资源,它需要受到进程的资源的限制。在同一个进程中,多线程它的资源是共享的,并进行Cpu分时间片处理。
在Java语言中,线程对资源的获取和利用的方式是抢占式。
2、如何创建线程:必须使用Thread类来创建该类的对象,并启动该对象的start()方法,
创建线程必须和Thread有关系,是通过Thread的构造函数来确定的。
1#:Thread:
继承Thread类
1) 定义子类继承Thread类。
public class MM extends Thread(){

}
2) 子类中重写Thread类中的run方法。
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
}
3) 创建Thread子类对象,即创建了线程对象。
4) 调用线程对象start方法:启动线程,调用run方法
public static void main(String[] args) {
// TODO Auto-generated method stub
MM m=new MM();
m.start();
}

    2#:Runnable 接口:     
       实现Runnable接口
            1)定义子类,实现Runnable接口。
            2)子类中重写Runnable接口中的run方法。
            3)通过Thread类含参构造器创建线程对象。
            4)将Runnable接口的子类对象作为实际参数传递给
                  Thread类的构造方法中。
            5)调用Thread类的start方法:开启线程,调用
                  Runnable子类接口的run方法。
package com.cn.hwadee;

public class Runn {

    public static void main(String[] args) {
        MyRunnable m = new MyRunnable(); 
        Thread t = new Thread(m); 
        t.start(); 
    }

}

class MyRunnable implements Runnable {

    @Override
    public void run() { 
        for (int i = 0; i < 100; i++) { 
            System.out.println("nn");
        }
    }

}

注:推荐使用创建接口的方式来创建线程,优点:
1) 可以避免单继承的局限性
2)可以让多个线程共享同一个接口类的对象,非常适合多线程处理同一份资源。(如果多线程处理同一个对象会出现同步问题)

3、 Thread类中方法:
1)获取或设置线程名称:getName(),setName(),创建线程的时候使用的名字给构造函数。setName()必须在线程执行之前设置,否则是无效。

2)static currentThread(): 返回当前执行线程 ,当我们使用接口的方式创建线程的时候,由于类本身不是线程类,所以不能直接使用线程函数的时候,我们可以获取出线程对象。

3)线程的调度;两种策略:
·1时间片:它给每个线程执行的期间的时间量是固定的,例如:都是执行40ms 【这个是我们不能修改的】
·2抢占式:线程是有高低优先级的,高优先级的获取CPU时间片的概率高。 【我们可以修改线程的优先级】

java中的线程的优先级:设置为10个级别,3个等级。 就是1-10的级别。
在创建线程的时候,默认的级别是5.
MAX_PRIORITY(10);
MIN _PRIORITY (1);
NORM_PRIORITY (5);
通过:setPriority(int newPriority):设置优先级
getPriority() :获取优先级

package cn.com.hwadee;

public class Runn {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
     NN n=new NN();
     Thread a=new Thread(n);
     Thread b=new Thread(n);
     a.setName("线程1");
     b.setName("线程2");
     a.setPriority(10);
     b.setPriority(1);
     a.start();
     b.start();
    }

}
class NN implements Runnable{

    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i=0;i<50;i++) {
            System.out.println(Thread.currentThread().getName()+","+i);
        }
    }

}

设置的高优先级的线程比低优先级的线程获取CPU的概率高 ,默认创建的线程是受父线程的优先级的继承值。
4): static void yield():线程让步: 暂停当前线程,然后把CPU的执行机会让给同优先级或高优先级的线程。如果没有同优先级的线程,系统会忽略这个方法的调用。

package com.cn.hwadee;

public class Demo6_Yield {


    public static void main(String[] args) {
        new MyThread().start();
        new MyThread().start();
    }

}

class MyThread extends Thread {
    public void run() {
        for (int i = 1; i <= 1000; i++) {
            if (i % 10 == 0) {
                Thread.yield(); 
            }
            System.out.println(getName() + "..." + i);
        }
    }
}

join() :当某个程序执行流中调用其他线程的 join() 方法时,调用线程将被阻塞,直到 join() 方法加入的 join 线程执行完为止。它有一个重载的函数,可以指定等待的时间(毫秒时间),如果指定时间超过,则继续运行。它主要用在需要得到子线程的结果后,才能继续运行的情况。

package cn.com.hwadee;

public class Runner1 {
        public static void main(String[] args) {
            MyThread a=new MyThread();
            MyThread b=new MyThread();
            MyThread c=new MyThread();
            a.setName("111");
            b.setName("222");
            c.setName("333");
            a.start();
            try {
                a.join();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            b.start();
            c.start();
        }

    }

    class MyThread extends Thread {
        public void run() {
            for (int i = 1; i <= 20; i++) {
                System.out.println(getName() + "..." + i);
            }
        }
}

5) static void sleep(long millis):(指定时间:毫秒) :令当前活动线程在指定时间段内放弃对CPU控制,使其他线程有机会被执行,时间到后重排队。注意和让步的区别:让步是如果没有线程在后面等待执行,则等于不让步,而睡眠sleep则必须要求线程放弃执行,并指定时间到了后再执行。

package cn.com.hwadee;

public class Runner1 {
        public static void main(String[] args) {
            MyThread a=new MyThread();
            a.setName("111");
            a.start();
        }

    }

    class MyThread extends Thread {
        public void run() {
            for (int i = 1; i <= 20; i++) {
                try {
                    Thread.sleep(1000*3);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(getName() + "..." + i);
            }
        }
}

4、线程的分类:针对java来说的:
1): 守护线程:它守护的用户线程。它是依赖于进程中的用户线程的,如果用户线程结束,则守护线程也就自动结束。
可以再线程启动之前调用thread.setDaemon(true) 把用户线程变为守护线程。如果创建该守护线程的用户线程,如果结束,则守护线程也就自动结束。
注意:守护线程由于会自动的终止,不能得到用户的控制,所以它不能完成一项比较要求高的功能。
在java的jvm中,java的垃圾回收线程就是一个典型的守护线程,在我们运行结束的时候,会自动停止垃圾回收线程。
2):用户线程:我们一般默认创建的为了完成某个功能的普通线程。
用户线程创建的子线程默认也是用户线程,守护线程创建的线程,默认是守护线程 可以通过isDaemon()进行验证判断

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值