线程和进程

本文详细介绍了Java中的线程概念,包括进程与线程的区别,线程的创建(Thread类、Runnable接口、Callable接口)及启动,线程的状态转换(新建、就绪、运行、阻塞、死亡),线程调度(分时调度、抢占式调度、线程优先级),以及线程的同步机制(同步代码块、同步方法、线程安全类)。此外,还探讨了线程的常用方法如sleep、wait、notify、yield和join等。
摘要由CSDN通过智能技术生成

        什么是进程:进程就是某种意义上相互隔离、独立运行的程序。

        什么是线程:线程就是进程执行的过程中的一个执行流程,一个线程可以由多个进程组成。他们可以分别执行不同的任务。多个线程同时运行称为并发。

        两者的区别:

        1、每个进程都有独立的代码和存储空间,进程的切换开销较大。

        2、线程没有对立的代码和存储空间,和所属的进程中的其他线程共享代码和存储空间。但是每个线程都有独立的运行栈和程序计数器,线程的切换开销较小。

        3、多进程—在操作系统中同时运行多个程序。

        4、多线程—在一个进程中有多个线程同时执行。


1、线程的创建和启动

        1.1、Thread类

        Thread代表线程类,主要有两个方法。一个是run()方法,用于执行程序启动时所执行的代码。另一个是start()方法,用于启动线程。

        创建线程类只需要继承Thread类,并覆盖run()方法即可。一个线程只能被启动一次。

public class MyThread extends Thread{
    @Override
    public void run(){
        System.out.println("我是被创建的线程");
    }
}

        1.2、Runnable接口

由于java是单继承,继承Thread后就不能继承其他类。故提供了java.lang.Runnable接口。

public class MyThread implements Runnable{
	@Override
	public void run{
		System.out.println("我是Runnable接口的实现类的run方法");
	}
}
public static void main(String arg[]){
	MyThread m1=new MyThread();//先创建Runnable实现类的对象
	Thread t1=new Thread(m1);//创建线程将m1作为参数传入
	t1.start;//启动线程
}

        1.3、Callable接口

        Callable接口用起来比较繁琐,但是可以提供线程的返回值。通过创建Callable的实现类重写call方法,在调用FutureTask方法将实现类传入。最后创建一个线程传入FutureTask对象才可以启动线程。启动线程后,通过FutureTask对象的get方法可以获取到创建的线程的返回值。

class MyThread implements Callable<Integer>{
    @Override
    public Integer call() throws Exception{
        int sum=0;
        for(int i=1;i<=100;i++){
            sum+=i;
        }
        return sum;
    }
    
    public static void main(String args[]){
        MyThread m1=new MyThread();
        FutureTask<Integer> task=new FutureTask<>(m1);
        Thread t1=new Thread(task);
        t1.start;
        int sum=task.get();
        System.out.print(sum);
    }
}

2、线程的状态转换

        新建状态(New):创建一个线程,在堆中为其分配内存。

        就绪状态(Runnable):当线程处于新建状态时,其他线程调用当前线程的start方式,该线程就进入了就绪状态,Java虚拟机会为其创建方法调用栈和程序计数器。处于这个状态的线程位于可运行池中,等待获取cup使用权。

        运行状态(Running):当线程处于就绪状态且占用到cpu使用权,执行程序代码。在并发环境中,如果计算机只有一个cup,那么任何时刻只会有一个线程处于运行状态。如果计算机有多个cpu,可以同时分配不同的线程占用不同的cpu,使他们都处于运行状态。只有处于就绪状态的线程才有机会运转到运行状态。

        阻塞状态(Blocked):当线程由于某些原因放弃cpu,暂停运行。当线程处于阻塞状态时,Java虚拟机不会为其分配cpu,直到其重新进入就绪状态后才有机会进入运行状态。

                如果执行了wait,Java虚拟机会把线程放入等待池中。

                当试图获得其他线程的同步锁时,如果已经被其他线程占用,会把线程放进锁池中。

                当执行打印或读取方法时,会发出I/O请求,进入阻塞。处理完毕,恢复运行。

        死亡状态(Dead):当程序退出run方法时,就进入死亡状态,表示该线程的生命周期结束。无论是否是正常死亡都不会影响其他线程的运行。


3、线程的调度

        调度模式分两种:分时调度模式抢占式调度模式

        分时式调度:平均分配,轮流获得cpu时间片。

        抢占式调度:优先级高的先运行,优先级相同随机选择。

        调整各个线程的优先级(Priority)

        所有处于就绪状态的线程根据优先级放入可运行池中,优先级高获得较高的运行几率。通过setPriority和getPriority设置和获取优先级。

        优先级最高为10,最低为1。

        线程睡眠Thread.sleep()

        当一个线程执行了sleep方法时,他就会放弃cpu,转到阻塞状态。线程的睡眠方法必须设置时间参数,当时间到了就会自动从阻塞状态转到就绪状态。如果采用了同步机制,当线程执行了sleep方法后不会释放掉锁

        线程等待wait()和唤醒notify()

        这个方法与线程睡眠相似,用起来很麻烦。通常情况下会在线程定义时通过标记位的方式使其等待,可以通过设置等待的时间,当时间到了就会自动从阻塞状态转到就绪状态。也可以通过notify()或者notifyAll()方法将其唤醒。与sleep不同的是,同步机制下当线程执行了wait()方法后,会释放同步锁

        线程让步Thread.yield()

        对于相同优先级的其他线程,如果其他线程处于就绪状态,那么yield方法把当前运行的线程放入可运行池中并使其他线程运行。如果没有相同级别的线程,yield方法什么也不做。

        等待其他线程结束Thread.join()

        当前运行的线程可以调用其他线程的join方法,当前运行方法进入阻塞状态,直至另一个线程运行结束,当前线程再恢复运行。

        停止线程方法stop()

        无论当前线程正在做什么,将其强制关闭。此方法已废弃

        中断线程interrupt()

        设置线程的中断状态位,可以通过线程的运行状态控制线程结束、等待新的任务或者继续执行当前任务。

        定时器TimerTask        

public static void main(String args[]){
    TimeTask task = new TimeTask(){
        public void run(){
            System.out.println("Time:"+new Date());
        }
    };
    ScheduledExecutorService sec = Executors.newScheduledThreadPool(1);
    //设置一次执行的任务
    sec.schedule(task,5000,TimeUnit.MILLISECONDS);
    //反复执行,固定频率的执行任务
    sec.scheduleAtFixedRate(task,0,3000,TimeUnit.MILLISECONDS);
    //反复执行,固定间隔的执行任务
    sec.scheduleWithFixedDelay(task,0,3000,TimeUnit.MILLISECONDS);    
}

4、线程的同步

        线程同步:当一个线程运行时,其他线程不能运行。(安全)

        线程异步:当一个线程运行时,其他线程也能运行。

        4.1、同步代码块

        在多线程的运行环境下,为了让共享数据可以正确的操作,同一时间只允许一个线程对共享数据进行修改。可以使用同步代码块(锁)。

public class MyThread implements Runnable{//创建一个Runnable接口的实现类
    int tickets=100;
    @Override
    public void run() {
        while (tickets>0){//共享代码块,同一时刻只有一个线程可以执行。
            synchronized (this){
                tickets--;
            }
            System.out.println(Thread.currentThread().getName()+":"+(tickets+1));
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}
    public static void main(String[] args) {//测试main方法,模拟卖票
        MyThread m1=new MyThread();
        Thread t1=new Thread(m1);
        Thread t2=new Thread(m1);
        Thread t3=new Thread(m1);
        t1.setName("1号售票员");
        t2.setName("2号售票员");
        t3.setName("3号售票员");
        t1.start();
        t2.start();
        t3.start();
    }

        4.2、同步方法

        使用synchronized方法修饰的方法为同步方法。同步方法和同步块一样都有线程安全的作用。

class mThread implements Runnable {
    int tickets=100;
    @Override
    public void run() {
        while (tickets>0){
            sale();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public synchronized void sale(){
        if(tickets>0){
            System.out.println(Thread.currentThread().getName()+":"+tickets);
            tickets--;
        }
    }
}
    public static void main(String[] args) throws InterruptedException {
        mThread m1 = new mThread();
        Thread t1=new Thread(m1);
        Thread t2=new Thread(m1);
        Thread t3=new Thread(m1);
        t1.setName("1号售票员");
        t2.setName("2号售票员");
        t3.setName("3号售票员");
        t1.start();
        t2.start();
        t3.start();
    }

        同步是共享竞争资源的有效手段,当一个资源已经在操纵共享资源时,其他线程只能等待。当操纵共享资源的线程执行同步代码后,其他线程再有机会操纵共享资源。为了提高性能,应尽可能减少共享代码块中的步骤,使得一个线程能尽快释放锁,减少其他线程的等待时间

        线程安全的类:能同时被多个线程访问,且访问结束后对象处于逻辑合理的状态。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值