java基础四(线程)

目录

1.概念

2.线程的实现

3.lamda简化线程

4.线程状态

4.1状态转换

5.并发和同步

5.1锁机制、同步块

6.通信

 

 

 

 

一、概念

  1、进程:一个进程对应一个程序。一个进程可以有多个线程。

  2、线程:是一个独立的执行路径。是程序中一个执行流。以CPU为主体。java中的线程是由虚拟CPU、代码、数据组成。代码和数据是相互独立的。代码和数据构成线程体,线程的行为由线程体决定。虚拟CPU是在创建线程时自动封装进Thread类的实例中。

  3、在程序运行时,即使自己没有创建线程,后台也会有多个线程。

  4、main()为主线程。为程序的入口。

  5、线程的调度由调度器安排,先后顺序是不能认为干预

  6、线程的优先级:priority设置。级别必须在1~10之间。并且优先级不代表执行的顺序

  7、守护线程(daemon):JVM不需要等待守护线程执行完,setDaemon(true)转换为守护程序

  8、死锁:多个线程占有一些共享资源,相互不释放。相互等待。造成死锁。

  9、线程的调度:在单个CPU上以某种顺序运行多个线程。

 

二、线程创建的三个方法

  1、继承Thread接口,重写run()方法

    基本步骤:继承接口,重写run方法,创建线程对象,使用start()开启线程。

    注意:

      执行线程必须调用start()方法才可以加入到调度器中。

      加入调度器不一定立即执行,需要等待调度器的分配执行

      如果直接调用run()方法。不是开启多线程。而是普通方法的调用。

    例子:使用线程执行1加到100的程序

public class text extends Thread{//继承Thread
    
    @Override
    public void run() {    //重写run()方法
        super.run();

        int num = 1;
        
        for(int i = 2; i <= 100; i++) {
            num += i;
        }
        System.out.println("1+2+3+.....+100="+num);
    }

    public static void main(String[] args){
        
        text tt = new text();//创建线程对象
        tt.start();    //开启线程
    }
}

 

  2、实现Runnable

    需要创建线程对象,目标对象,再启动线程。

    优点:避免单继承的局限性。使用接口。方便共享。

    例子:使用Runnable计算1加到100

public class text implements Runnable{//实现Runnable
    
    @Override
    public void run() {    //重写run()方法

        int num = 1;
        
        for(int i = 2; i <= 100; i++) {
            num += i;
        }
        System.out.println("1+2+3+.....+100="+num);
    }

    public static void main(String[] args){
        
        text tt = new text();//创建目标对象
        Thread th = new Thread(tt);//创建线程对象。
        th.start();//开启线程
        
        //如果是使用一次。可以使用匿名写法。
        //new Thread(tt).start();
    }
}

 

  3、实现Callable 

    需要的步骤:创建目标对象、创建执行服务、提交执行、获取结果、关闭服务

    一般出去工作一段时间后,才可能使用到。

public class text implements Callable{//实现Callable
    
    @Override
    public Object call() throws Exception {//重写call()
        
        int num = 1;
        
        for(int i = 2; i <= 100; i++) {
            num += i;
        }
        System.out.println("1+2+3+.....+100="+num);
        
        return true;
    }

    public static void main(String[] args) throws 
    InterruptedException, ExecutionException{
        
        //(1)创建目标对象
        text tt = new text();
        //(2)创建执行服务
        ExecutorService es = Executors.newFixedThreadPool(1);
        //(3)执行服务
        Future<Boolean> submit = es.submit(tt);
        //(4)获取结果
        boolean object = submit.get();
        //(5)关闭服务
        es.shutdownNow();
            
    }
}

返回顶部

 

三、lamda表达式

  为了避免匿名内部类过多,属于函数式编程的概念。

  1、只用一次(并且没有参数和返回值)

  后续补充

 

四、线程状态

  

 

  导致线程就绪状态转换的方法:

    调用start()、阻塞解除、调用yield()、JVM本身的线程切换。

 

  导致阻塞状态转换的方法:

    调用sleep()、wait()、Join()、IO中的read()、write()

 

  几个方法:

  currentThread:返回当前线程。 isAlive:判断当前线程是否活着。

  suspend:暂停线程。如果想要恢复这个线程,一定要其他线程调用resume恢复当前线程。

返回顶部 

 

  转换方法

    1、线程停止(使用boolean)

      JDK提供的stop()、destroy() 已经被jdk废弃的了。所以不用这个

      可以设置一个boolean值。进行线程的开启和停止。

    

    2、线程暂停(sleep)

      可以使用sleep(时间),进行睡眠时间的设置,达到一个线程暂停的效果。

      时间是毫秒数。而且,sleep不会释放锁的。

 

    3、线程礼让(yield)

      礼让线程是让当前的线程暂停。不是阻塞,将当前线程从运行状态转入就绪状态。

      让cpu重新调度。

 

    4、线程插队(Join)

      插队,就是阻塞当前正在运行的线程。等待插队线程执行完了。在执行其他线程。

      是一个阻塞状态。

 

    5、interrupt

      如果一格线程正在处于阻塞时,使用interrupt方法将使该线程中断的状态被清除。并且该线程会接收到InterruptExcaption异常。

返回顶部 

 

五、并发和同步

  并发:是同一个对象多个线程同时操作。

  同步:是一个等待机制。多个需要访问同一个对象的线程进入等待池形成队列。需要等待前面的线程使用完毕后,下一个线程再使用这个资源。

  临界区:一个程序中单独的、并发的线程对同一个对象进行访问的代码段,也可以是语句块。

  对象锁:将每个由synchronize语句指定的对象设置成一个锁。是一种独特的排它锁。如果一个线程获得对象的锁后,便拥有了对象的操作权,其他任何线程不能对该对象进行任何操作。

  

  线程的安全:需要形成队列、并且使用锁机制。

    1、获得对象的排它锁后,独占资源,其他线程必须等待。

    2、多线程竞争下,加锁、释放锁导致比较多的上下文切换和调度延迟。引起性能问题

    3、如果优先级高的线程等待优先级低的线程,会优先导致,引起性能问题

 

  锁机制、synchronize块

    每一个对象都对应一把锁,每一个synchronize方法必须获得调用该方法的对象锁才可以执行。

    否则,该线程阻塞。方法一旦执行,就会独占该锁。直到方法返回时,才将锁释放。被阻塞的

    线程才能获取该锁,重新进入可执行状态。

 

    synchronize同步块:synchronize(obj){ },obj称为同步监视器

    任何对象都可以作为同步监视器。

    同步方法无需指定同步监视器,因为同步方法的同步监视器是对象本身。

 

    在容器CopyOnWriteArrayList<类型>中已经有集成的锁机制了。

 返回顶部

 

六、通信

  

  在图中。仓库在有货品的时候,需要通知消费者。然后没有货的时候,通知生产者

  这样一个消息的传递(通信)

 

  因为synchronize同步块,可以阻止并发更新同一个共享资源,实现同步。

  但是,不能实现不同线程之间的通信问题。

 

  解决通信问题:

    1、只能在同步方法或者同步代码中使用一下方法。可以解决通信问题。

    wait():线程一直等待,直到线程通知。与sleep()不同。会释放锁。

    notifiy(): 唤醒一个处于等待状态的线程

    ontifyAll():唤醒同一个对象上所有调用wait()方法的线程。优先级高的优先调度

 

    2、管程

      并发协作模型“生产者/消费者模式”,就是管程。

      在生产者和消费者之间设置一个缓冲区。容器存在数据,消费者可以消费,

      数据为空,消费者等待,生产者可以进行生产。数据满了,生产者等待

 

    3、进行boolean的设置。像信号灯一样     

       就是使用布尔值,进行开关的设置,注意:不要忘记了等待之后,需要再切换回来。

 

    4、定时调度

      使用Timer、Timetask实现定时启动某个线程。

 返回顶部

 

        

posted @ 2019-12-31 13:53  JAHC  阅读(250)  评论(0)    收藏  举报