Java多线程详解

什么是多线程:

程序:是为完成特定任务,用某种编程语言编写的一组指令的集合。
进程:指正在运行的一个程序,是系统进行资源分配和调用的独立单位,每个进程都有自己的内存空间和系统资源。
线程:进程可进一步细化为线程,是一个程序内部的一条执行路径

如果程序的进程有多个线程,就叫多线程程序,如果程序在运行时只有一条执行路径,就叫单线程程序;比如说我们有一个杀毒软件,当我们想清理垃圾或者查杀病毒的时候,必须一个个来,在做完其中一件事的时候才能开始下一件事,这叫单线程;如果边清理垃圾边查杀病毒,2个可以同时进行,在时间上是重叠的,就叫多线程。
当一个Java程序启动的时候,会有一个线程立即开始运行,这个线程通常被我们叫做程序中的主线程,因为它是在我们程序开始的时候就被执行的线程。

  • 子线程都从该线程中被孵化

  • 通常它都是最后一个执行结束的线程,因为它会执行各种的关闭操作。
    如下图:
    img

线程基本状态及生命周期:

线程包括NEW(新建)RUNNABLE(就绪)RUNNING(运行)BLOCKED(阻塞)DEAD(死亡).五种状态。

如图:

在这里插入图片描述

首先创建线程对象,调用start()方法后这个线程有执行资格,进入就绪状态。但只有在抢到CPU的执行权的时候才能执行。如果run()执行方法完毕或者被关闭,那么线程死亡;如果在运行的过程中被其他线程抢走CPU的执行权就会回到就绪状态,如果在运行时被阻塞方法阻塞,直接失去执行资格,要等阻塞结束后才能重新获得资格并进入就绪状态。

如何实现多线程:

  • 继承Thread类
  • 实现Runable接口

Thread类也实现了Runable接口,所以都需要重写里面的Run()方法;使用Runable接口可以避免继承的局限性,因为一个类可以实现多个接口,继承只有单继承。但在使用时也没有特别大的差别,最大的不同是一个是具体的类,一个是抽象的接口

Runable接口只有一个run()方法;主要的成员变量有name(变量名称), priority(线程优先级),target(会被运行的对象)等等,如下:

private volatile String name;    

private int            priority;    

private Thread         threadQ;    

private long           eetop;     

/* Whether or not to single_step this thread.*/  



private boolean     single_step;    

/* Whether or not the thread is a daemon thread.  */   

private boolean     daemon = false;    

/* JVM state. */  

private boolean     stillborn = false;     

/* What will be run.*/    

private Runnable target;     

/* The group of this thread. */  

private ThreadGroup group; 

Thread类主要的方法:

Thread Thread.currentThread() :获得当前线程的引用。获得当前线程后对其进行操作。
void interrupt() :中断线程。(将中断状态标记为true)
boolean interrupted()测试当前线程是否已经中断。
void sleep(long millis)休眠指定时间
void sleep(long millis, int nanos)休眠指定时间
void yield()暂停当前正在执行的线程对象,并执行其他线程。
String getName()返回该线程的名称。
int getPriority()返回线程的优先级。
Thread.State getState()返回该线程的状态。
void join() :等待该线程终止。
void join(long millis) :等待该线程终止的时间最长为 millis 毫秒。
void join(long millis, int nanos) :等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。
void run() :线程启动后执行的方法。
void start():使该线程开始执行;Java 虚拟机调用该线程的 run 方法。

关于start()方法和run()方法的区别:

start()方法会使得该线程开始执行;java虚拟机会去调用该线程的run()方法。

run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有

一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。

关于sleep()和wait()的异同:

sleep() 方法是线程类(Thread)的静态方法,让调用线程进入睡眠状态,让出执行机会给其他线程,等到休眠时间结束后,线程进入就绪状态和其他线程一起竞争cpu的执行时间。

因为sleep() 是静态方法,他不能改变对象的锁,当一个synchronized块中调用了sleep() 方法,线程虽然进入休眠,但是对象的机锁没有被释放,其他线程依然无法访问这个对象。如果不在synchronized块中,sleep()方法会让正在执行的线程主动让出CPU(然后CPU就可以去执行其他任务),在sleep指定时间后CPU再回到该线程继续往下执行(sleep方法只让出了CPU,而并不会释放同步资源锁)

wait()是Object类的方法,指当前线程让自己暂时退让出同步资源锁,以便其他正在等待该资源的线程得到该资源进而运行,只有调用了notify()方法,之前调用wait()的线程才会解除wait状态,可以去参与竞争同步资源锁,进而得到执行。

​ **区别:sleep()方法可以在任何地方使用;wait()方法则只能在同步方法或同步块中使用;sleep()是线程线程类(Thread)的方法,调用会暂停此线程指定的时间,但监控依然保持,不会释放对象锁,到时间自动恢复;wait()是Object的方法,调用会放弃对象锁,进入等待队列,待调用notify()/notifyAll()唤醒指定的线程或者所有线程,才会进入锁池。

编程测试:

三个黄牛同时抢200张票,打印出哪个黄牛买了第几张票

使用Runable接口实现多线程:

public class SellTicket implements Runnable {
    private int tickets = 200;
    private Object obj=new Object();
    @Override
    public void run() {
        while (true) {
            synchronized (obj) {		//同步代码块
                if (tickets > 0) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":" + "第"+(200- tickets+1)+"张票" );
                    tickets--;
                }else
                    return;
            }
        }
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        SellTicket sell = new SellTicket();

        Thread thread1 = new Thread(sell,"黄牛A");
        Thread thread2 = new Thread(sell,"黄牛B");
        Thread thread3 = new Thread(sell,"黄牛C");

        thread1.start();
        thread2.start();
        thread3.start();

    }
}

编写一个程序,启动三个线程,三个线程的ID分别是A,B,C;每个线程将自己的ID值在屏幕上打印5遍,打印顺序是ABCABC…重复三遍

打印类:

public class PrintfID {
    private int flag=1;

    public synchronized void printfA() {    //打印A,下同
        while (flag != 1) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.print(Thread.currentThread().getName() + ":" + Thread.currentThread().getId());
        flag = 2;
        this.notifyAll();       //同步非静态方法的锁是this对象,下同
    }

    public synchronized void printB() {
        while(flag!=2) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.print(Thread.currentThread().getName() + ":" + Thread.currentThread().getId());
        flag=3;
        this.notifyAll();
    }

    public synchronized void printC() {
        while(flag!=3) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.print(Thread.currentThread().getName() + ":" + Thread.currentThread().getId());
        flag=1;
        this.notifyAll();
    }

}

测试类:

public class Test {
    public static void main(String[] args) {
        PrintfID printfID = new PrintfID();
        //创建三个线程
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    printfID.printfA();
                }
            }
        },"A");

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    printfID.printB();
                }
            }
        },"B");

        Thread thread3 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    printfID.printC();
                }
            }
        },"C");
        //启动线程
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

结果:

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值