Java基础(多线程)

一、线程概述

1.1进程

在一个操作系统中,每个独立执行的程序都可称为一个进程。

在多任务操作系统中,进程并不是同时运行的。在计算机中所有的应用程序都是由cpu执行的,对于一个cpu而言同一时间点只能运行一个程序。由于运行速度快,看起来像同时执行多个进程。

1.2线程

一个进程中可以有多个执行单元同时运行,称为线程。操作系统中的每一个进程中都至少存在一个线程。

多线程是指一个进程在执行过程中可以产生多个单线程,单线程程序在运行时相互独立且可以并发执行。

线程与进程一样由cpu轮流执行。

二、线程的生命周期及状态转换

线程的生命周期可以分为五个阶段,分别是新建状态、就绪状态、运行状态、阻塞状态和死亡状态,具体关系如下图。

1.新建状态(New)

创建了线程对象后该线程对象就处于新建状态,此时仅占有内存,不能运行。

2.就绪状态(Runnable)

调用了线程对象的start()方法后该线程对象进入就绪状态。处于就绪状态的线程位与线程队列中,等待系统的调度。

3.运行状态(Running)

只有处于就绪状态的线程才可能转换到运行状态。一个线程启动后不会一直处于运行状态。

4.阻塞状态(Blocked)

一个正在执行的线程在特殊情况下会暂时中止自己的执行,进入阻塞状态。县城从阻塞状态只能进入就绪状态,结束阻塞的线程需要重新进入可运行池中,等待系统调度。

5.死亡状态(Terminated)

调用stop()或run()方法正常执行完毕,或线程抛出一个未捕获的异常(Exception)、错误(Error),线程进入死亡状态。一旦进入死亡状态,县城不再拥有运行的资格,也不能再转换到其他状态。

三、线程的创建

3.1继承Thread类创建多线程

//单线程
class Mythread{
    public void run(){
        while(true){
            System.out.println("Mythread类的run()方法正在执行");
        }
    }
}
public class Main{
    public static void main(String[] args){
        Mythread mythread = new Mythread();
        mythread.run();
    }
}

通过继承Thread类,并重写Thread类中的run()方法可以实现多线程。Thread类中提供了start()方法用于启动新线程,线程启动后虚拟机会自动调用run()方法。

//多线程
class Mythread extends Thread{
    public void run(){
        while(true){
            System.out.println("Mythread类的run()方法正在执行");
        }
    }
}
public class Main{
    public static void main(String[] args){
        Mythread mythread = new Mythread();
        mythread.start();
        while(true){
            System.out.println("Main()方法正在执行");
        }
    }
}

单线程的程序在运行时会按照代码的调用顺序执行,多线程中同时运行,互不影响。

3.2实现Runnable接口创建多线程

为了克服多重继承的弊端,Thread类提供了另一个构造方法Thread(Runnable target),使用该构造方法时,需为该方法传递一个实现了Runnable接口的实例对象。

其中Runnable是一个接口,只有一个run()方法。

//多线程
class Mythread implements Runnable{
    public void run(){
        while(true){
            System.out.println("Mythread类的run()方法正在执行");
        }
    }
}
public class Main{
    public static void main(String[] args){
        Mythread mythread = new Mythread();
        Thread thread = new Thread(mythread);
        thread.start();
        while(true){
            System.out.println("Main()方法正在执行");
        }
    }
}

3.3两种方式的比较

多个线程运行同一个程序,即资源共享,需要用到第二种方式创建多线程。

class TicketWindow implements Runnable{
    private int tickets = 100;
    public void run(){
        while(true){
            if(tickets > 0){
                Thread th = Thread.currentThread(); //获取当前线程
                String th_name = th.getName();
                System.out.println(th_name"正在发售第"+tickets--+"张票");    
            }
        }
    }
}
public class Main{
    public static void main(String[] args){
        TicketWindow tw = new TicketWindow();
        new Thread(tw,"窗口1").start();
        new Thread(tw,"窗口2").start();
        new Thread(tw,"窗口3").start();
        new Thread(tw,"窗口4").start();
    }
}

注意,每个线程都有自己的名字,主线程默认名字为"main",用户创建的第n个线程的名字默认为"Thread-n-1".如果希望指定线程的名字,可以调用setName(String name)方法为线程设置名称。

四、线程的调度

Java虚拟机会按照特定的机制为程序中的每个线程分配cpu的使用权,这种机制称为线程的调度。

线程调度有分时调度模型和抢占式调度模型两种。

分时调度模型,是指让所有的线程轮流获得cpu的使用权,平均分配每个线程占用cpu的时间片。

抢占式调度模型,是指让可以运行池中优先级高的线程优先占用cpu,优先级相同则随机选择,时java虚拟机的默认调度模型。

4.1线程的优先级

线程的优先级用1-10的整数表示,数字越大优先级越高。也可以用Thread类中提供的3个静态常量表示,static int MAX_PRIORITY/MIN_PRIORITY/NORM_PRIORITY。

程序在运行期间,处于就绪状态的每个线程都有自己的优先级,如main线程具有普通优先级。可以通过Thread类的setPriority(int newPriority)方法设置。

4.2线程休眠

可以使用Thread的静态方法sleep(long millis)使正在执行的线程暂停。该方法声明会抛出InterruptedException异常,因此调用时应该捕获异常,或者声明抛出异常。

4.3线程让步

可以通过Thread的yield()方法实现线程让步,让正在执行的线程将cpu资源让给其他线程执行。

yield()方法与sleep()方法的区别是,它不会阻塞该线程,而是将其转换成就绪状态。

调用该方法后,只有与当前线程优先级相同或者更高的线程才能获得执行机会。

4.4线程插队

在某个线程中调用其他线程的join()方法,该线程会被阻塞,直到被join方法加入的线程执行完成后,被阻塞的线程才会继续运行。

五、多线程同步

5.1线程安全问题

线程安全问题由多个线程同时处理共享资源所导致,要想解决该问题,必须保证任何时刻只有一个线程访问共享资源。

5.2同步代码块

当多个线程使用同一个共享资源时,可以将处理共享资源的代码放在一个使用synchronized关键字修饰的代码块中,该代码块称为同步代码块。

synchronized(lock){
操作共享资源代码块
}

lock是个锁对象,是同步代码块的关键。当某一个线程执行同步代码块时,其他线程将无法执行当前同步代码块,发生阻塞。

等当前线程执行完同步代码块后,所有的线程开始抢夺执行权,抢到的进入同步代码块。

注意,同步代码块中的锁对象可以是任意类型的对象,但多个线程共享的锁对象必须是唯一的。

锁对象的创建代码不能放到run()方法中。

5.3同步方法

也可以在方法前用synchronized关键字修饰,称为同步方法。

同步方法也有锁,他的锁是调用该方法的对象。

5.4死锁问题

两个线程都需要对方所占用的锁,且无法释放自己的锁,都处于挂起状态时,称为死锁。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值