多线程

多线程

一、进程线程的区别:

  • 进程是操作系统资源分配的基本单位,线程是CPU的基本调度单位。
  • 一个程序运行后至少有一个进程。
  • 一个进程至少包含一个线程。
  • 进程间不能共享数据段地址,但同进程的线程之间可以。

二、线程的组成:

  • CPU时间片:操作系统(OS)会为每个线程分配执行时间。
  • 运行数据:
    • 堆空间:存储线程需使用的对象,多个线程可以共享堆中的对象。
    • 栈空间:存储线程需要使用的局部变量,每个线程都拥有独立的栈。

三、线程的特点:

  • 线程抢占式执行(效率高、可防止单一线程长时间独占CPU)。
  • 在单核CPU中,宏观上同时执行,微观上顺序执行。

四、创建线程

  • 继承Thread类,重写run方法。
  • 实现Runnable接口
  • 实现Callable接口

五、获取和修改线程名称

  • 获取线程ID和线程名称

    • 在Thread的子类中调用this.getId()或者this.getName()。只适合继承Thread类

      class MyThread extends Thread{
          @Override
          public void run() {
              int sum=0;
              for (int i=0;i<=100;i++){
                  //this.getId()获取线程ID,this.getName()获取线程名称
                  System.out.println("线程ID:"+this.getId()+"线程名称:"+this.getName()+"子线程------"+i);
              }
          }
      }
      
    • 使用Thread.currentThread().getId()和Thread.currentThread().getName()。可以不继承Thread类

      class MyThread extends Thread{
          @Override
          public void run() {
              for (int i=0;i<=100;i++){
                  System.out.println("线程ID:"+Thread.currentThread().getId()+"线程名称:"+Thread.currentThread().getName()+"子线程------"+i);
              }
          }
      }
      
  • 修改线程名称

    • 调用线程对象的setName()方法。

      //创建线程对象
              MyThread myThread = new MyThread();
              MyThread myThread1 = new MyThread();
              //修改线程名称
              myThread.setName("QQ");
              myThread1.setName("微信");
      
    • 使用线程子类的构造方法赋值。

      package com.sun.base.XianCheng;
      
      public class TestThread {
          public static void main(String[] args) {
             //创建线程对象
              MyThread myThread = new MyThread("QQ");
              MyThread myThread1 = new MyThread("微信");
       ...
       /**
       * 线程类
       */
      class MyThread extends Thread{
          public MyThread(){
      
          }
          public MyThread(String name) {
              super(name);
          }
          ...
      

继承Thread类--代码实现四个窗口各卖一百张票案例

package com.sun.base.XianCheng;

public class TestThread {
    public static void main(String[] args) {
       //创建线程对象
        MyThread myThread = new MyThread("窗口1");
        MyThread myThread1 = new MyThread("窗口2");
        MyThread myThread2 = new MyThread("窗口3");
        MyThread myThread3 = new MyThread("窗口4");
        //启动线程,不能run方法
        myThread.start();
        myThread1.start();
        myThread2.start();
        myThread3.start();
    }
}
/**
 * 卖票窗口类(线程类)
 */
class MyThread extends Thread{
    private int ticket=100; //100张票
    public MyThread(){

    }
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        //买票功能
        while (true){
            if (ticket<0){
                break;
            }
            System.out.println("线程ID:"+Thread.currentThread().getId()+"线程名称:"+Thread.currentThread().getName()+"卖了第"+(100-ticket)+"张票");
            ticket--;
        }
    }
}

实现Runnable接口

package com.sun.base.XianCheng;

public class TextRunnable {
    public static void main(String[] args) {
        //匿名内部类 创建可运行对象
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i=0;i<100;i++){
                    System.out.println(Thread.currentThread().getName()+"----"+i);
                }
            }
        };
        //创建线程对象
        Thread thread = new Thread(runnable, "我的子线程");
        //启动线程
        thread.start();
        for (int i=0;i<50;i++){
            System.out.println("主线程----"+i);
        }
    }
}

六、线程的方法

  • 休眠(限期等待):public static void sleep(long millis) 当前线程主动休眠millis毫秒
public void run() {
                for (int i=0;i<100;i++){
                    System.out.println(Thread.currentThread().getName()+"----"+i);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
  • 放弃:public static void yield() 当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片
public void run() {
                for (int i=0;i<100;i++){
                    System.out.println(Thread.currentThread().getName()+"----"+i);
                    //主动放弃
                    Thread.yield();
                }
            }
  • 加入(无限期等待):public final void join() 允许其他线程加入到当前线程中

    • 在启动线程之后,加入当前线程,并阻塞当前线程,直到加入线程执行完毕
  • 优先级

    • 线程对象.setPriority();在线程启动之前
    • 线程优先级为1-10,默认为5,优先级越高,表示获取CPU机会越多。
  • 守护线程

    • 线程对象.setDaemon(true);设置为守护线程。在线程启动之前
    • 线程有两类:用户线程(前台线程)、守护线程(后台线程)
    • 如果程序中所有前台线程都执行完毕了,后台线程就会自动结束
    • 垃圾回收器线程属于守护线程
  • 线程通信

    • 等待:public final void wait() / public final void wait(long timeout)
    • 通知:public final void notify() / public final void notifyAll()

七、线程安全

  • 同步方式

    • 同步代码块 synchronized(临界资源对象){//对临界资源对象加锁

      //代码(原子操作)} //每个对象都拥有一个互斥锁标记,用来分配给线程。只有拥有对象互斥锁标记的线程,才能进入对该对象加锁的同步代码块。

      private Object obj =new Object();
          @Override
          public void run() {
              while (true) {
                  synchronized (obj) {
                      if (ticket < 0) {
                          break;
                      }
                      System.out.println(Thread.currentThread().getName() + "卖了第" + (100 - ticket) + "张票");
                      ticket--;
                  }
              }
          }
      
    • 同步方法 synchronized 返回值类型 方法名称(形参列表){//对当前对象(this)加锁

      //代码(原子操作)}

      //卖票方法
          public synchronized boolean sale(){//锁 this ;如果是静态方法 锁 Ticket.class
              if (ticket<0){
                  return false;
              }
              System.out.println(Thread.currentThread().getName() + "卖了第" + (100 - ticket) + "张票");
              ticket--;
              return true;
          }
      
posted @ 2020-12-09 21:30  某人很酷  阅读(96)  评论(0)    收藏  举报