Java并发编程之美(java并发编程基础篇)

什么是线程

线程是CPU调度的最小单位。是进程的组成部分,一个进程至少包含一个线程

线程的创建与运行

java创建线程的方式jdk提供了3种方式,这里不包括线程池创建

  1. 继承Thread类,并且重写Threadrun方法,实例化Thread对象 并且运行线程的start方法
 class ThreadOne extends Thread{
	    @Override
	    public void run(){
	        for(;;){
	            System.out.println("running");
	        }
	    }
	}
 public static void main(String[] args) {
        Thread one = new ThreadOne();
        one.start();
    }
  1. 实现Runnable接口,重写run方法,创建Thread对象并且将实现Runnable接口的实例传入Thread的构造函数
 class  ThreadTwo implements Runnable{
    @Override
    public void run() {
        for (;;){
            System.out.println("running");
        }
    }
 }
 public static void main(String[] args) {
        Thread two = new Thread(new ThreadTwo());
        two.start();
    }

3.实现Callable接口,并且从写call方法,创建FutureTask对象 ,将实现Callable接口的线程传入FutureTask的构造函数,再创建Thread对象,将FutureTask对象传入Thread的构造函数,运行Threadstart方法

 class ThreadThree implements Callable<String>{
    @Override
    public String call() throws Exception {
        System.out.println("running");
        return "running";
    }
 }
 public static void main(String[] args) {
      FutureTask<String> futureTask = new FutureTask<>(new ThreadThree());
        Thread three = new Thread(futureTask);
        three.start();
    }

实现Callable接口与另外2种不同的是,该线程可以拥有返回值 ,在实现接口的时候可以传入泛型指定改线程的返回值。然后再调用futureTask.get()获取返回值,如果没有线程没有执行完毕 那么获取改线程接口的线程会阻塞等待

线程通知与运行

线程的通知notifynotifyAll,wait方法,

  1. 线程的运行(run方法)
    当线程被创建,调用线程的start()方法及运行,注意这里的运行并不是线程执行,而是处于就绪状态,必须等到它拿到CPU的执行权才能真正运行。
  2. 线程的等待(wait方法)
    waitnotifynotifyAll方法是 Object的方法, 而Object是所有类的父类。并不是线程的方法,所以再使用wait以及notity等方法的时候,必须获取到这个对象的监视器锁,而这个监视器锁的获取方法就是使用synchronized关键字获取这个Object的锁
    当调用object的wait方法而没有获取锁的时候,就会抛出IllegalMonitorStateException异常
     public static void main(String[] args) {
          Object object = new Object();
          try {
              object.wait();
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      }
     Exception in thread "main" java.lang.IllegalMonitorStateException
 //正确方式
    Object object = new Object();
      try {
          synchronized (object){
              object.wait();
          }
      } catch (InterruptedException e) {
          e.printStackTrace();
      }

调用wait方法会让当前线程处于WAIT状态,当其他线程调用对象锁对象的notify或者notifyAll方法。notify方法与notifyAll方法的不同在于notify只会唤醒一个等待种的线程 而具体唤醒哪一个线程取决于哪个线程抢占到了CPU的执行权 所以说synchronized是一个非公平锁,它不能保证先进入等待状态的线程先被唤醒。

public class TestWait {
   public static void main(String[] args) throws InterruptedException {
       Object object = new Object();
       new Thread(()->{
           synchronized (object){
               try {
                   System.out.println("线程一进入等待");
                   object.wait();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               System.out.println("线程一执行完毕");
           }
       }).start();
       new Thread(()->{
           synchronized (object){
               try {
                   System.out.println("线程二进入等待");
                   object.wait();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               System.out.println("线程二执行完毕");
           }
       }).start();
       new Thread(()->{
           synchronized (object){
               try {
                   System.out.println("线程三进入等待");
                   object.wait();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               System.out.println("线程三执行完毕");
           }
       }).start();
       Thread.sleep(2000);
       synchronized (object){
           object.notify();
       }
   }
}

启动了3个线程。3个线程获取到监视器锁之后 都进入了等待 同时说明了 wait方法会释放它得到的锁对象 从而别的而线程会获取到锁,进入等待状态,主线程睡眠2秒后,获取到锁对象,调用notify方法,唤醒等待3个线程中的其中一个。

线程一进入等待
线程二进入等待
线程三进入等待
线程一执行完毕

然而线程并未结束,因为还有线程二和线程三处于等待状态。

   synchronized (object){
            object.notifyAll();
        }
线程一进入等待
线程二进入等待
线程三进入等待
线程三执行完毕
线程二执行完毕
线程一执行完毕

notifyAll方法会拥有改锁对象的所有等待线程。
wait方法还拥有一个参数,

    public final native void wait(long timeout) throws InterruptedException;

该方法传入一个超时时间 单位为毫秒。表示该线程最多等待timeout的时间,如果没有被其他线程唤醒,那么就再timeout后重新进入cpu执行权的抢占。
当然再wait的时候,是可以被其他线程打断的,

  Thread thread = new Thread(() -> {

            synchronized (object) {
                try {
                    System.out.println("线程三进入等待");
                    object.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程三执行完毕");
            }
        });

        thread.start();
        Thread.sleep(2000);
        thread.interrupt();

线程thread运行后获取监视器锁后,进入等待。主线程睡眠2秒后 执行线程的thread的 interrupr方法 ,那么该线程也是会被终止的。

    线程三进入等待
   java.lang.InterruptedException
   线程三执行完毕
   	at java.lang.Object.wait(Native Method)
   	at java.lang.Object.wait(Object.java:502)
   	at com.iron.man.TestWait.lambda$main$2(TestWait.java:44)
   	at java.lang.Thread.run(Thread.java:748)
   Process finished with exit code 0

等待线程执行终止的join方法

再实际运用中往往会出现一个需求,方法一和方法二再运行,必须等待他们运行结束后 再运行方法三,这时候就需要使用join方法。join方法是线程的方法,表示调用join方法的线程执行完毕之后 才能继续执行其他的线程。

让线程睡眠的sleep方法

让出CPU执行权的yield方法

线程中断

理解线程上下文切换

线程死锁

ThreadLocal

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值