【JAVA入门】进程与线程

发布于:2022-12-24 ⋅ 阅读:(354) ⋅ 点赞:(0)

目录

思维导图

一、进程

二、线程

1、多线程的实现方式一

2、线程实现方法二

3、线程同步

4、线程安全的类

5、Lock锁

三、生产者消费者模式


思维导图

 

一、进程

进程:正在运行的程序

  • 是系统惊醒资源分配和调用的独立单位

  • 每个进程都有他自己的内存空间和系统资源

二、线程

线程概念:是进程中的单个顺序控制流,是一条执行路径

单线程:一个进程如果只有一条执行路径,成为单线程程序

多线程:一个进程如果有多条执行路径,成为多线程程序

1、多线程的实现方式一

1.1、实现步骤

(1)定义一个MyThread类继承自Thread类

(2)在MyThread类中重写run方法;

(3)创建MyThread类的对象

(4)启动线程

//定义一个MyThread类继承自Thread类
public class MyThread extends Thread {
    @Override
    //在MyThread类中重写run方法;
    public void run() {
        for (int i=0;i<100;i++){
            System.out.println(i);
        }
    }
}
============================================================================
public class Demo2 {
   public static void main(String[] args) {
      //创建MyThread类的对象
     MyThread my1=new MyThread();
     MyThread my2=new MyThread();
     //启动线程
//      my1.run();//只调用run方法并不能实线多线程
//      my2.run();
      my1.start();
      my2.start();
  }
}

问题:

为什么要重写run()方法?

因为run()是用来封装被线程执行的代码

run()和start()的区别?

run():封装线程执行的代码,直接调用,相当于普通方法调用

start():启动线程;然后由Java虚拟机调用run()方法

1.2、 设置和获取线程名称

Thread类中设置和获取线程名称的方法

setName(String name):将此线程的名称为参数name

getName(String name):返回此线程名称,默认Thread-0、Thread-1.......

//定义一个MyThread类继承自Thread类
public class MyThread extends Thread {
    public MyThread(){}
    public MyThread(String name){
        super(name);
    }
    @Override
    //在MyThread类中重写run方法;
    public void run() {
        for (int i=0;i<100;i++){
            //getName(String  name):返回此线程名称
            System.out.println(getName()+":"+i);
        }
    }
}
​
=============================================================================
public class Demo2 {
   public static void main(String[] args) {
      //方法一
      //创建MyThread类的对象(无参构造)
     MyThread my1=new MyThread();
     MyThread my2=new MyThread();
     //setName(String   name):将此线程的名称为参数name
      my1.setName("q");
      my2.setName("w");
      //方法二
     //创建MyThread类的对象(有参构造)
      MyThread my3=new MyThread("e");
      MyThread my4=new MyThread("t");
     //启动线程
      my1.start();
      my2.start();
      //currentThread()返回当前正在执行的的线程对象的引用
      System.out.println(Thread.currentThread().getName()); 
  }
}

1.3、线程调度

线程的两种调度模式

分时调度模型:所有线程轮流使用CPU使用权,平均分配每个线程CPU的时间片

抢占式调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取CPU时间片相对多一些。

线程优先级默认值是5,范围是1-10

线程优先级高仅仅表示线程获取CPU时间片的几率高,但是要在此时较多或多次运行时才能显现效果。

Java使用的是抢占式调度模型

       System.out.println(my1.getPriority());//获取线程优先级
       my1.setPriority(10);//设置线程优先级
       System.out.println(Thread.MIN_PRIORITY);//线程最低优先级
       System.out.println(Thread.MAX_PRIORITY);//线程最高优先级

1.4、线程控制

static void sleep(long milis):使用当前正在执行的线程停留(暂停执行)指定的毫秒数

void join( ):其他线程必须等待这个线程死亡才能执行

void setDaemon(boolean on):将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出

//定义一个MyThread类继承自Thread类
public class MyThread extends Thread {
    public MyThread(){}
    public MyThread(String name){
        super(name);
    }
    @Override
    //在MyThread类中重写run方法;
    public void run() {
        for (int i=0;i<100;i++){
            //getName(String  name):返回此线程名称
            System.out.println(getName()+":"+i);
            try {
                //使用当前正在执行的线程停留(暂停执行)指定的毫秒数
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
=============================================================================
public class Demo2 {
   public static void main(String[] args) throws InterruptedException {
      //创建MyThread类的对象(无参构造)
     MyThread my1=new MyThread();
     MyThread my2=new MyThread();
     //setName(String   name):将此线程的名称为参数name
      my1.setName("q");
      my2.setName("w");
     //设置主线程
       Thread.currentThread().setName("e");
       //主线程功能
       for (int i=0; i<10;i++){
           System.out.println(Thread.currentThread().getName()+":"+i);
       }
       //设置守护线程
       my1.setDaemon(true);
       my2.setDaemon(true);
      // 启动线程
      my1.start();
      //其他线程需等待my1执行结束才能开始执行
      my1.join();
      my2.start();
  }
}

1.5、线程生命周期

2、线程实现方法二

2.1、实现步骤:实现Runnable接口

(1)定义一个MyRunnable实现Runnable接口

(2)在MyRunnable类中重写run()方法

(3)创建Runnable类的对象

(4)创建Thread类的对象,把MyRunnable对象作为构造方法的参数

(5)启动线程

//定义一个MyRunnable类实现Runnable接口
public class MyRunnable implements Runnable{
    @Override
    //在MyThread类中重写run方法;
    public void run() {
        for (int i=0;i<100;i++){
            //Thread.currentThread().getName(String  name):返回此线程名称
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}
==============================================================================
public class Demo2 {
   public static void main(String[] args) throws InterruptedException {
      //创建MyRunnable类的对象
       MyRunnable my=new MyRunnable();
       //创建Thread类的对象,把MyRunnable对象作为构造方法的参数(默认线程名)
       Thread t1=new Thread();
       Thread t2=new Thread();
       //Thread(Runnable target,String name) :创建Thread对象时给线程命名
       Thread t3=new Thread(my,"a");
       Thread t4=new Thread(my,"b");
       //启动线程
       t1.start();
       t2.start();
  }
}

相比继承Thread类,实现Runnable接口的好处?

避免了Java单继承的局限性

适合多个相同程序的代码去处理同一个资源的情况,把线程和程序代码、数据有效分离,较好的体现了面向对象的设计思想

3、线程同步

3.1、同步代码块

格式

synchronized(任意对象){

多条语句操作共享数据的代码

}

synchronized(任意对象):相当于给代码块加锁,任意对象可以看成是一把锁

同步的好处和弊端

好处:解决了多线程的数据安全问题

弊端:当线程很多时,因为每个线程都会去判断同步上的锁,会降低程序的运行效率

3.2、同步方法

同步方法:把synchronized关键字加到方法上

格式

修饰符 synchronized 返回值类型 方法名(方法参数){}

public synchronized void methoed (){}

同步方法的锁是this

同步静态方法:把synchronized关键字加到静态方法上

格式

修饰符 static synchronized 返回值类型 方法名(方法参数){}

public static synchronized void methoed (){}

同步静态方法的锁是类名.class的到类的字节码对象

4、线程安全的类

StringBuffer

线程安全,可变的字符序列

JDK5后被StringBuilder替代,通常应该使用StringBuilder类,因为他支持所有相同的操作,单他更快,因为他不执行同步

Vector

改进了List接口,会被同步,如果不需要线程安全的实现,建议使用ArrayList代替

Hashtable

该类实现了 一个哈希表,将键映射到值,任何非null对象都可以作为键或者值

实现map接口,会被同步,如果不需要线程安全的实现,建议使用HashMap代替

5、Lock锁

Lock锁提供比使用synchronized 方法和语句可以获得更广范的锁定操作

Lock中提供获得锁和释放锁的方法

void lock(): 获得锁

viod unlock(): 释放锁

Lock是接口不能被实例化,采用他的实现类ReentrantLock来实例化

ReentrantLock的构造方法

ReentrantLock():创建一个ReentrantLock的实例

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//定义一个MyRunnable类实现Runnable接口
public class MyRunnable implements Runnable{
    private Lock lock= new ReentrantLock();
    private int i;
    @Override
    //在MyThread类中重写run方法;
    public void run() {
        while (true){
            try{
           lock.lock();//获得锁
           if (i>0){
               try {
                   Thread.sleep(10);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               System.out.println(i);
           }}finally {
                lock.unlock();//释放锁
            }
    }} 
}

三、生产者消费者模式

1、生产者消费者模式概述

该模式包含两类线程

(1)生产者线程用于生产数据

(2)消费者线程用于消费数据

为了解耦生产者与消费者的关系,通常会采用共享的数据区域

为了体现生产和消费过程中的等待和唤醒,Java提供了等待和唤醒方法

void wait():使当前线程等待,直到另一个线程调用该对象的notify()方法或者notifyAll()方法

void notify(): 唤醒正在等待对象监视器的单个线程

void notifyAll():唤醒正在等待对象监视器的所有线程

   private int milk;
    private boolean state=false;
    public synchronized void put(int milk) throws InterruptedException {
       //有则等待
        if (state){
            wait();
        }
        //无则生产
        this.milk=milk;
        //生产后改变状态
        state =true;
        //唤醒其他线程
        notifyAll();
    }

本文含有隐藏内容,请 开通VIP 后查看