java多线程基础部分

基本概念

  • 进程:进程拥有独立的代码和数据空间,是资源分配的最小单位。一个进程可以包含一个或多个线程。
  • 线程:同一类的线程共享代码和数据空间,每个线程都拥有独立的运行栈和程序计数器。线程是cpu调度的最小单位。
  • 进程/线程 的五个状态:创建就绪运行阻塞终止
  • 多进程代表操作系统可运行多程序,线程代表程序里运行多个顺序流

创建java线程

java创建线程有三种方法

  • 基础Thread类
  • 实现Runable接口
  • 实现Callable接口,配合Future、线程池

继承Thread

class threadLearn extends Thread{
    public void run(){
        //...
    }
}
public class Main{
    public static void main(){
        ThreadLearn learn = new ThreadLearn ();
        learn.start();
    }
}

实现java.lang.Runnable接口

class ThreadLearn implements Runnable{
    @Override
    public void run(){
        //...
    }
}
public class Main{
    public static void main(){
        ThreadLearn learn = new ThreadLearn ();
        learn.start();
    }
}
  1. start()方法使线程变成可运行状态Runnable,操作系统决定何时调用运行。
  2. start()方法重复调用会抛出java.lang.IllegalThreadStateException异常
  3. run()方法是多线程程序的一个约定,所有的多线程代码都要写在里面。

ThreadRunnable比较

  1. Thread本质上是实现了Runnable接口。
  2. Thread类实现了Runnable并在其之上进行了拓展。

线程状态

线程状态转换
线程状态 状态分类 描述
新建状态New - 新创建了一个线程对象
就绪状态Runnable - 其它线程调用了该线程的start()方法,线程变为可运行
运行状态Running - 就绪状态的线程被系统调用。
阻塞状态Blocked - 分为三种情况
阻塞状态 等待阻塞 运行的线程执行wait()方法
阻塞状态 同步阻塞 获取同步锁时锁被其它线程占用,jvm会把该线程放入锁池之中
阻塞状态 其它阻塞 线程运行sleep()join()的线程结束或发出I/O请求。sleep不会释放锁
死亡状态 - 线程执行完毕或异常退出

线程调度

  1. 线程优先级
  • Thread的setPriortity()getPriortity()管理优先级
  • 优先级取值1~10整数,推荐使用常量,这三个级别的可移植性好。
static int MAX_PRIORITY=10;
static int NORM_PRIORITY=5;//默认
static int MIN_PRIORITY=1;
  1. 线程睡眠
    Thread.sleep(long millis):设定线程阻塞时间,阻塞结束后进入就绪状态。

  2. 线程等待
    Object类中的wait()方法,导致当前线程等待,直到其它线程调用此对象的notify()方法或者notifyAll()唤醒,等价于wait(0)

  3. 线程让步
    Thread.yield()暂停当前正在执行的线程对象,把执行的机会让给优先级相同或更高的线程。

  4. 线程加入
    join()当前线程进入阻塞态,调用其它线程,该线程运行完毕后当前线程再进入就绪态。

  5. 线程唤醒
    Object类的notify()方法,唤醒对象监听器上一个线程,如果有多个线程在此对象上等待,则唤醒随机一个。notifyAll()唤醒所有该对象上等待的线程。
    wait()sleep()都可以通过interrupt()方法 打断线程的暂停状态 ,从而使线程立刻抛出InterruptedException

sleep方法不会释放锁,wait
waitnotifynotifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用

常用方法

  • sleep(): 强迫一个线程睡眠N毫秒。
  • isAlive(): 判断一个线程是否存活。
  • join(): 等待线程终止。
  • activeCount(): 程序中活跃的线程数。
  • enumerate(): 枚举程序中的线程。
  • currentThread(): 得到当前线程。
  • isDaemon(): 一个线程是否为守护线程。
  • setDaemon(): 设置一个线程为守护线程。(用户线程和守护线程的区别在于没有用户线程后守护线程终止)
  • setName(): 为线程设置一个名称。
  • wait(): 强迫一个线程等待。
  • notify(): 通知一个线程继续运行。
  • setPriority(): 设置一个线程的优先级。

线程同步

synchronized[ˈsɪŋkrənaɪzd]是系统级的锁,一旦锁死除了线程自行释放没有其它方法。juc的lock锁是编码级别的,可以代码解锁。juc(java.util.concurrent)下次讨论

  • synchronized在对象里:标记于方法或是代码块都是对对象加锁。只要对象中出发了锁,整个对象都无法进入。
  • synchronized标记于静态方法,则是对于类加锁,和对象锁不冲突

线程数据传递

同步情况下使用参数传入,return返回的形式,多线程下运行和结束是不可预料的,所以无法和同步一样传参。

  1. 使用构造方法传参
//线程使用构造函数就收这个参数
Thread thread = new MyThread1("hello world");   
  1. set方法
    线程里先设置set方法接受参数(不用多说了吧)
    然后start()之前设置参数
MyThread2 myThread = new MyThread2();   
myThread.setName("hello world");   
Thread thread = new Thread(myThread);   
thread.start();   
  1. 回调函数

将对象传入线程,线程在某一时间调用对象的函数。主线程通过传入的对象获取线程操作后的值。(还有静态类)

  1. 声明lambda函数的接口
public interface ICallback {   
    public void callback(Map params);  
} 
  1. 线程调用接口返回数据
public static void doStm(final ICallback callback) {  
        // 初始化一个线程  
        Thread t = new Thread() {  
            public void run() {  
  
                // 这里是业务逻辑处理  
                System.out.println("子线任务执行:"+Thread.currentThread().getId());
  
                // 为了能看出效果 ,让当前线程阻塞5秒  
                try {  
                    Thread.sleep(1000);
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
  
                // 处理完业务逻辑,  
                Map params = new HashMap();
                params.put("a1", "这是我返回的参数字符串...");
                callback.callback(params);
            };  
        };  
  
        es.execute(t);
        //一定要调用这个方法,不然executorService.isTerminated()永远不为true
        es.shutdown();
    }
 doStm((params)->{
            System.out.println("单个线程也已经处理完毕了,返回参数a1=" + params.get("a1"));
        });

你可能感兴趣的:(java多线程基础部分)