Java之多线程

这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战

Java 多线程编程

Java 给多线程编程提供了内置的支持。 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销。

这里定义和线程相关的另一个术语 - 进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守护线程都结束运行后才能结束。

多线程能满足程序员编写高效率的程序来达到充分利用 CPU 的目的。

什么是Java多线程?

1、进程与线程

▶进程

  • 当一个程序被运行,就开启了一个进程, 比如启动了qq,word
  • 程序由指令和数据组成,指令要运行,数据要加载,指令被cpu加载运行,数据被加载到内存,指令运行时可由cpu调度硬盘、网络等设备

▶线程

  • 一个进程内可分为多个线程
  • 一个线程就是一个指令流,cpu调度的最小单位,由cpu一条一条执行指令

并行与并发

▶并发:单核cpu运行多线程时,时间片进行很快的切换。线程轮流执行cpu

▶并行:多核cpu运行 多线程时,真正的在同一时刻运行

创建多线程

继承 Thread 类

public class test0 {

    public static void main(String[] args) {
        Thread MyThread = new MyThread();
        MyThread.start();
    }
}

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("hello myThread" + Thread.currentThread().getName());
    }
}
复制代码

实现 Runnable

public class test0 {

    public static void main(String[] args) {

        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
    }
}

class MyRunnable implements Runnable{
    @Override
    public void run(){
        System.out.println("hello myRunnable" + Thread.currentThread().getName());
    }
}
复制代码

暂停

Java中线程的暂停是调用java.lang.Thread类的sleep方法(注意是类方法)。该方法会使当前正在执行的线程暂停指定的时间,如果线程持有锁,sleep方法结束前并不会释放该锁。

Java示例:

public class Main {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            System.out.print(i + " ");
            try {
                Thread.sleep(1000);    //当前main线程暂停1000ms
            } catch (InterruptedException e) {
            }
        }
    }
}
复制代码

上述代码中,当main线程调用Thread.sleep(1000)后,线程会被暂停,如果被interrupt,则会抛出InterruptedException异常。

互斥

Java中线程的共享互斥操作,会使用synchronized关键字。线程共享互斥的架构称为监视(monitor),而获取锁有时也称为“持有(own)监视”。

每个锁在同一时刻,只能由一个线程持有。
注意:synchronized方法或声明执行期间,如程序遇到任何异常或return,线程都会释放锁。

1、synchronized方法

//synchronized实例方法
public synchronized void deposit(int m) {
    System.out.print("This is synchronized method.");
}
复制代码

注:synchronized实例方法采用this锁(即当前对象)去做线程的共享互斥。

//synchronized类方法
public static synchronized void deposit(int m) {
    System.out.print("This is synchronized static method.");
}
复制代码

注:synchronized类方法采用类对象锁(即当前类的类对象)去做线程的共享互斥。如上述示例中,采用类.class(继承自java.lang.Class)作为锁。

2、synchronized声明

public void deposit(int m) {
    synchronized (this) {
        System.out.print("This is synchronized statement with this lock.");
    }
    synchronized (Something.class) {
        System.out.print("This is synchronized statement with class lock.");
    }
}
复制代码

注:synchronized声明可以采用任意锁,上述示例中,分别采用了对象锁(this)和类锁(something.class)

3、等待(wait)和通知(notify)

Object有两个很重要的接口:Object.wait()和Object.notify()

当在一个对象实例上调用了wait()方法后,当前线程就会在这个对象上等待。直到其他线程调用了这个对象的notify()方法或者notifyAll()方法。notifyAll()方法与notify()方法的区别是它会唤醒所有正在等待这个对象的线程,而notify()方法只会随机唤醒一个等待该对象的线程。

wait()、notify()和notifyAll()都需要在synchronized语句中使用

4、中断

java.lang.Thread类有一个interrupt方法,该方法直接对线程调用。当被interrupt的线程正在sleep或wait时,会抛出InterruptedException异常。
事实上,interrupt方法只是改变目标线程的中断状态(interrupt status),而那些会抛出InterruptedException异常的方法,如wait、sleep、join等,都是在方法内部不断地检查中断状态的值。

  • interrupt方法

Thread实例方法:必须由其它线程获取被调用线程的实例后,进行调用。实际上,只是改变了被调用线程的内部中断状态;

  • Thread.interrupted方法

Thread类方法:必须在当前执行线程内调用,该方法返回当前线程的内部中断状态,然后清除中断状态(置为false) ;

  • isInterrupted方法

Thread实例方法:用来检查指定线程的中断状态。当线程为中断状态时,会返回true;否则返回false。