java线程知识

线程核心:锁

对于共享资源,在多线程的环境中,是会存在竞争情况的,由于竞争的存在,导致在使用共享资源的情况,会出现意想不到的情况。如果共享资源仅仅是可读的,不管多少线程来操作,也不会出现线程安全的情况。但如果在使用共享资源的时候,会改变共享资源的状态,那么基本会出现线程安全的问题。
锁是什么呢?既然资源存在竞争,那么当一个线程在占用了资源后,想办法告知其他想使用其资源的线程当前资源正在占用中,让其等候,相当于把资源锁住了,即每个对象都关联一个锁,且是唯一的。
注:核心概念还是锁,需要明白锁在java中是如何体现的

线程状态

在这里插入图片描述

wait()/notify()/notifyAll()使用

public class ThreadTest {

  public static void main(String[] args) {
      Object lockObject = new Object();
      Thread t1 = new Thread(new Runnable() {
          @Override
          public void run() {
              synchronized (lockObject) {
                  try {
                      System.out.println("t1 start");
                      lockObject.wait();
                      lockObject.notify();
                      System.out.println("t1 end");
                  }catch (Exception e) {

                  }
              }
          }
      });
      Thread t2 = new Thread(new Runnable() {
          @Override
          public void run() {
              synchronized (lockObject) {
                  try {
                      System.out.println("t2 start");
                      lockObject.wait();
                      lockObject.notify();
                      System.out.println("t2 end");
                  }catch (Exception e) {

                  }
              }
          }
      });
      Thread t3 = new Thread(new Runnable() {
          @Override
          public void run() {
              synchronized (lockObject) {
                  try {
                      System.out.println("t3 start");
                      // 限时等待,调用这个方法后会释放锁,处于等待状态,1秒之后会进入
                      //等待获取锁的队列
                      lockObject.wait(1000);
                      System.out.println("t3 notify");
                      // 只要是通知其他调用了wait方法的线程,让这些线程可以重新进入等待获取锁的队列
                      lockObject.notify();
                      System.out.println("t3 end");
                  }catch (Exception e) {

                  }
              }
          }
      });
      t3.start();
      t1.start();
      t2.start();
  }

执行结果:
t3 start
t1 start
t2 start
t3 notify
t3 end
t1 end
t2 end

分析:t1、t2、t3三个线程开始的顺序是不确定的。t1执行到wait()方法后,t1线程会进入等待状态,并释放lockObject这个锁,同理,t2和t3线程也会进入等待状态,并释放线程锁。但t3线程不同(lockObject.wait(1000)),会在1s后重新进入等待获取线程队列。此时并没有线程持有锁,所有t3在1s之后能够获取此锁继续往下执行,然后调用notify方法,当t1或者t2某一个收到此信号后,也会进入等待获取锁队列(只能有一个进入,如果调用notifyAll方法,两个线程都能进入队列。),此时t3还没有执行完,即锁还没有释放,等t3执行完后,释放锁。则进入等待获取锁队列的线程就有可以获取锁了,继续执行,然后调用notify方法,另一个线程也能按照此步骤继续往下执行了。

join方法

此方法是线程中的一个方法,平常也没怎么用到,这个方法可以控制线程的执行顺序,内部也是wait和notify的机制。

public class ThreadTest {

    public static void main(String[] args) {
        Object lockObject = new Object();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("t1 start");
                System.out.println("t1 end");
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    t1.join();
                    System.out.println("t2 start");
                    System.out.println("t2 end");
                }catch (Exception e) {

                }
            }
        });
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    t2.join();
                    System.out.println("t3 start");
                    System.out.println("t3 end");
                }catch (Exception e) {

                }
            }
        });
        t3.start();
        t1.start();
        t2.start();
    }

通过上面的写法,可以控制t1的线程执行完之后,t2线程的任务再执行,t2线程中的任务执行完之后,t3线程执行。

synchronized

这个关键字没啥好说的,最常用的保证线程安全的关键字,这个关键字保证了:可见性、防止重排序、原子性。

ReentrantLock

基本原理:ReentrantLock被称之为重入锁,即如果当前线程获取了此锁,再次获取时,可以获取成功,将获取锁的次数进行加一操作。借助如Unsafe这个类的操作,即常常听到的CAS(Compare And Swap)操作。

AbstractQueuedSynchronizer:AQS,这个类非常核心,给一个阻塞锁和同步器提供了一个基本框架,比如ReentrantLock、ContDownLatch、Semaphore等。

public class ThreadTest {

    private static final ReentrantLock lock = new ReentrantLock();

    private static int i = 0;

    public static void increment()  {
        try {
            // 等待获取锁,除非收到中断信号
            lock.lockInterruptibly();
            // 一直等着获取锁
            lock.lock();
            // 尝试获取锁,如果锁被其他线程保持着,直接返回false,否则返回true
            // 这里得进行判断,如果获取锁失败了,调用unlock()方法会抛出异常
            lock.tryLock();
            // 在规定时间范围内获取锁,返回true,如果在固定时间范围内,锁还被其他线程拿着则则返回false。
            // 这里得进行判断,如果获取锁失败了,调用unlock()方法会抛出异常
            lock.tryLock(1, TimeUnit.SECONDS);
            i++;
        }catch (InterruptedException e) {

        }
        try {
            i++;
        }finally {
            lock.unlock();
            lock.unlock();
            lock.unlock();
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                Stream.iterate(1, item -> item + 1).limit(1000).forEach(i -> increment());
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Stream.iterate(1, item -> item + 1).limit(1000).forEach(i -> increment());
                }catch (Exception e) {

                }
            }
        });
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                Stream.iterate(1, item -> item + 1).limit(1000).forEach(i -> increment());
            }
        });
        t3.start();
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        t3.join();
        System.out.println(i);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值