JavaSE多线程

vampire 2020年09月15日 10次浏览

JavaSE多线程

1、进程与线程

进程与线程区别: 本质区别在于,每个进程拥有自己的一整套变量,而线程则共享数据。共享变量使得线程之间的通信比进程之间的通信更有效、更方便。

线程状态:

1554290786198

2、java多线程实现

java线程创建调用流程

1554291874356

  • 继承Thread类实现多线程
package test;

class MyThread extends Thread{
    private String title;
    public MyThread(String title){
        this.title = title;
    }
    @Override
    public void run() {
        for (int i=0; i<10; i++){
            System.out.println(this.title+", i = "+i);
        }
    }
}
public class TestDemo {
    public static void main(String[] args) {
        MyThread myThread1 = new MyThread("thread1");
        MyThread myThread2 = new MyThread("thread2");
        MyThread myThread3 = new MyThread("thread3");
        myThread1.start();
        myThread2.start();
        myThread3.start();
    }
}

  • Runnable()接口实现多线程(更好的描述程序共享)
package test;

class MyThread implements Runnable{
    private String title;
    public MyThread(String title){
        this.title = title;
    }
    @Override
    public void run() {
        for (int i=0; i<10; i++){
            System.out.println(this.title+", i = "+i);
        }
    }
}
public class TestDemo {
    public static void main(String[] args) {
        MyThread myThread1 = new MyThread("thread1");
        MyThread myThread2 = new MyThread("thread2");
        MyThread myThread3 = new MyThread("thread3");
        new Thread(myThread1).start();
        new Thread(myThread2).start();
        new Thread(myThread3).start();
    }
}

注意: Runnable接口对象可以采用匿名内部类或者Lambda表达式来定义

/**
 * 使用匿名内部类创建线程
 */
//public class TestDemo {
//    public static void main(String[] args) {
//       new Thread(new Runnable() {
//           @Override
//           public void run() {
//               System.out.println("Hello World");
//           }
//       }).start();
//    }
//}

/**
 * 使用Lambda表达式创建线程
 */
public class TestDemo {
    public static void main(String[] args) {
        Runnable runnable = () -> {
            System.out.println("Hello World");
        };
        new Thread(runnable).start();
    }
}
  • Thread和Runnable的关系

    Thread代理类

    MyThread真实类

    	多线程的设计中,使用了代理设计模式的结构,用户自定义的线程主体负责项目核心功能的实现,辅助实现通过Thread类实现.
    	在进行Thread启动多线程的时候调用的是start()方法,而后找到run()方法;但通过Thread的构造方法传递Runnable接口对象的时候,该接口对象被Thread类中的target属性保存,start()方法执行调用Thread中的run()方法,该run()方法调用Runnable接口子类对象的run()方法。
    	多线程开发的本质在于多个线程可以进行同一资源的抢占。
    
  • Callable实现多线程

import java.util.concurrent;
class MyThread implements Callable<String>{
    private int ticket = 10;
    @Override
    public String call() throws Exception{
        while(ticket>0){
            System.out.println("剩余票数:" + this.ticket--);
        }
        return "票卖完了";
    }
}
public  class TestDemo{
    public static void main(String[] args) {
        FutureTask<String> task = new FutureTask<>(new MyThread());
        new Thread(task).start();
        new Thread(task).start();
        try {
            System.out.println(task.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
  • 解释Runnable与Callable的区别?
    • Runnable是jdk1.0的实现接口;Callable是jdk1.5的实现接口
    • java.lang.Runable接口之中只提供一个run()方法,并且没有返回值
    • java.util.concurrent.Callable接口提供有call()方法,可以有返回值

3、线程常用操作方法

​ 定义在Thread中

  • 线程的命名和取得

    • 构造方法 public Thread(Runnable target, String name);
    • 设置名字 public final void setName(String name);
    • 取得名字 public final String getName();
    • 获取当前线程 public static Thread currentThread();

    每一个JVM进程都会有线程

    主线程负责整体流程,而子线程负责处理耗时操作

    ​ 主线程可以创建若干个子线程

  • 线程的休眠

    某个线程暂缓执行

    public static void sleep(long millis) throws InterruptedException
    public static void sleep(long millis, int nanos) throws InterruptedException
    参数 
    millis - 以毫秒为单位的睡眠时间长度 
    nanos - 0-999999额外的纳秒睡眠
    休眠期间产生中间异常
    
    • 产生多个线程进行休眠

      package com.yrd.myThread;
      
      public class ThreadDemo {
          public static void main(String[] args) {
              for (int num = 0; num < 5; num++){
                  new Thread(()->{
                      for (int x=0; x<10; ++x){
                          System.out.println(Thread.currentThread().getName() + "x = " + x);
                          try {
                              Thread.sleep(1000);
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          }
                      }
                  }, "线程对象" + num).start();
              }
      
          }
      }
      
      
  • 线程中断

    线程休眠可以被打断,Thread里面提供的终端执行的处理方法:

    • 判断线程是否被执行:public boolean isInterrupted()
    • 中断线程执行:public void Interrupt()
  • 线程强制执行

    当满足某些条件之后,某一个线程对象可以一直独占资源,一直到任务结束

    • 强制执行 public final void join() throws InterruptedException
  • 线程礼让 public static void yield()

  • 线程优先级

    线程的优先级越高越有可能先执行(越有可能抢占资源)

    • 设置优先级 public final void setPriority(int newPriority)
      • MIN_PRIORITY = 1
      • MAX_PRIORITY = 10
      • NORM_PRIORITY = 5
    • 获取优先值
      • public final int getPriority()

4、线程的同步和死锁

多线程处理中利用Runnable描述多个线程操作的资源,Thread描述线程对象,多个线程访问同一资源时处理不当会发生数据错误

  • 同步处理

  • 线程死锁