你的位置:首页 > 信息动态 > 新闻中心
信息动态
联系我们

【java基础】线程的生命周期、创建的两种方式及使用、线程的同步

2021/11/6 15:31:40

目录

 一、概念

1、程序、进程、线程

二、线程的创建和使用

1、通过继承Thread类的方式

2、通过实现Runnable接口的方式:

3、Thread类中的相关方法

4、线程优先级

三、线程的生命周期

 1、线程的几种状态

四、线程的同步

 1、同步代码块

2、同步方法


 一、概念

1、程序、进程、线程

 程序:是为了完成某个任务,利用某种语言编写的一组指令的集合,及指一块静态的代码

 进程:是程序的一次执行的过程,也可以是一个正在运行的程序,是一个动态的过程,有他自己产生、运行、消亡的过程-----------即生命周期。

         线程:进程可以进一步细化为线程,程序在运行中,内部的一条执行路径。若一个程序内部并行执行了多条路径,即为多线程。

                    而线程作为调度和执行的单位,拥有独立的运行栈和程序技术器,一个进程内的多个线程共享相同的内存单元和内存地址空间,从同一个堆中分配对象,访问相同的对象和变量。但是多个线程操作共享的变量和对象,会带来安全隐患

二、线程的创建和使用

1、通过继承Thread类的方式

步骤:

①:创建一个Thread的子类

②:重写Thrad类中run()方法,将执行此线程的操作声明在run()方法中

③:实例化当前子类的对象

④:调用Thread类中的start方法

//创建Thread子类
class MyThread extends Thread {

    //重写Thread类中run方法
    public void run() {

//将此线程执行的操作声明在run方法中
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                System.out.print(Thread.currentThread().getName() + ":" + i);//输出当前线程的线程名和i
            }
        }
    }
}

public class ThreadTest12 {
    public static void main(String[] args) {
//创建Thread子类的对象
        MyThread mt = new MyThread();
//调用start方法:1、启动当前线程;2、调用当前线程的run()方法
        mt.start();
    }
}

这种方式有两个问题:

①、我们不能通过直接调用run()方法来启动线程

②、再启动一个线程,不能让已经执行start()方法的线程去执行,否则会报错:

IllegalThreadStateException

2、通过实现Runnable接口的方式:

步骤:

①:创建一个实现了Runnable接口的类

②:重写Runnable类中的抽象方法:run()

③:创建此实现类的对象

④:将此实现类的对象作为参数传递到Thrad类的构造器中,创建Thread类的对象

⑤:调用Thread类中的start方法

class MyThread implements Runnable {

    public void run() {
//将此线程执行的操作声明在run方法中
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                System.out.print(Thread.currentThread().getName() + ":" + i);//输出当前线程的线程名和i
            }
        }

    }
}


public class ThreadTest {
    public static void main(String[] args) {
        //创建实现类的对象
        MyThread mt = new MyThread();
        //将此实现类的对象作为参数传递到THread构造其中,创建Thread类的对象
        Thread ta = new Thread(mt);//体现了多态性
        //调用Thread类中的start()方法
        ta.start();

        Thread ta1 = new Thread(mt);//体现了多态性
        ta1.start();//再启动一个线程,执行run方法,注意:此时两条线程操作同一个对象

    }


}

总结:比较两种线程创建的方式:

1、在开发中优先使用:实现Runnable接口的方式

原因:

①:实现的方式没有类的单继承的局限性

②:实现的方式更适合处理多线程有共享数据的情况

两者之间的练习:

①:Thread类本身也是实现了Runnable接口中的run方法

②:都需要重写run方法

③:都要将线程需要执行的操作声明在run方法中

3、Thread类中的相关方法

void start():启动线程,并执行对象的run()方法

run():线程再被调度是执行的操作

String getName():返回当前对象的名称

void setName(String name):设置当前线程的名称

static Thread currentThread():返回当前线程,在Thread子类中就是this,通常用于主线程和Runnable实现类

static void yield():线程让步,暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程

                                   若队列中没有同优先级的线程,则忽略此方法

join():当某个程序执行流中,调用其他线程的join方法时,调用线程将被阻塞,直到join方法加入的join方法执行完为止

static void sleep(long millis)(指定时间:毫秒):

①:令当前活动线程在指定时间内放弃对cpu的控制,使其他线程有机会被执行,时间到后重新排队

②:抛出InterruptedException异常

stop():强制结束线程声明周期,不推荐使用

boolean  isAlive:判断线程是否还活着

4、线程优先级

同优先级线程组成先进先出队列(先到先服务),使用时间片策略

对优先级线程,采用优先调度的抢占式策略(高优先级的线程抢占CPU)

线程的优先级等级:

MAX_PRIORITY:10

MIN_PRIORITY:1

NORM_PRIORITY:5

涉及的相关方法:

getPriority()返回相关线程的优先级登记

setPriority(int newPriority)设置相关线程的优先级登记 

注意点:

线程创建时继承父线程的优先级

低优先级的只是获得调度的概率低,并非一定是高优先级完成后才能调度

三、线程的生命周期

 1、线程的几种状态

四、线程的同步

前序:当某个线程在执行的过程中,尚未完成操作时,        其他线程参与进来,会导致线程安全问题,以下两种方式可以解决(思路:当一个线程在操作共享数据时,让其他线程不能参与进来,直到线程a操作完,其他线程才能进来,这样即使线程a发生阻塞,也不能被改变)

 1、同步代码块

synchronized(同步监视器){  //同步监视器:俗称:锁,任何一个类的对象都可以称当锁,要求多个线程必须共用一把锁!

//需要被同步的代码

}

①:继承Thread子类的方式结合同步代码块

//创建Thread子类
class MyThread extends Thread {

    //重写Thread类中run方法
    public void run() {

synchroinzed(this){ //可以使用当前对象,不过继承Thread类的方式慎用this
//将此线程执行的操作声明在run方法中
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                System.out.print(Thread.currentThread().getName() + ":" + i);//输出当前线程的线程名和i
                }
            }
        }
    }
}

public class ThreadTest12 {
    public static void main(String[] args) {
//创建Thread子类的对象
        MyThread mt = new MyThread();
//调用start方法:1、启动当前线程;2、调用当前线程的run()方法
        mt.start();
    }
}

②:实现Runnable接口的方式结合同步代码块

class Window1 implements Runnable{
    private int ticket = 100;
    Object obj = new Object();
    @Override
    public void run() {
        while (true){
            synchronized(this) { //使用当前对象也可以,此时的this:唯一的window1的对象
                if (ticket > 0) {

                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + ":" + ticket);
                    ticket--;
                } else {
                    break;
                }
            }
        }
    }
}

public class WindowTest1 {
    public static void main(String[] args) {
        Window1  w = new Window1();
        Thread t =new Thread(w);
        Thread t1 =new Thread(w);
        Thread t2=new Thread(w);
        t.start();
        t1.start();
        t2.start();
    }
}

2、同步方法

①:通过实现Runnable接口的方式结合同步方法

//使用同步方法解决实现Runnable接口的线程安全问题
 
class Window3 implements Runnable {
    private int ticket = 1000;

    @Override
    public void run() {
        while (true) {
            show();
        }
    }

    public synchronized void show() { //同步监视器:this
        //  synchronized (this) {
        if (ticket > 0) {
/*                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }*/
            System.out.println(Thread.currentThread().getName() + ":" + ticket);
            ticket--;
        }
        //   }
    }

}


public class WindowTest3 {
    public static void main(String[] args) {
        Window3 w = new Window3();
        Thread t = new Thread(w);
        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        t.start();
        t1.start();
        t2.start();
    }
}

②:通过继承Thread类的方式结合同步方法

/**使用同步方法处理继承Thread类的方式中的线程安全问题
 *
 * 关于同步方法的总结:
 * 1、同步方法仍然涉及到同步监视器,只是不需要我们显式的声明
 * 2、非静态的同步方法,同步监视器是:this
 *    静态的同步方法:同步监视器是当前类本身
 *
 */
class Window4 extends Thread {

    private static int ticket = 100;

    //变成唯一,使用static


    @Override
    public void run() {
        while (true) {
            show();
        }
    }

    private static synchronized void show() {//同步监视器:Window.class
        //private synchronized void show()//这种方法是错的,进来的是三个对象
        if (ticket > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket);
            ticket--;
        }
    }
}

public class WindowTest4 {
    public static void main(String[] args) {
        Window4 w = new Window4();
        Window4 w1 = new Window4();
        Window4 w2 = new Window4();

        w.setName("窗口1");
        w1.setName("窗口2");
        w2.setName("窗口3");

        w.start();
        w1.start();
        w2.start();
    }
}