Java 多线程相关的使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zgkxzx/article/details/80964173

线程的创建

1.继承Thread类,重写run方法;
2.实现Runnable接口 重写run方法;

区别
使用Runnable接口的更适合面向对象的思想,可以使线程类继承其他父类。多个线程处理一个Runnable等问题。

join/wait/notify

join 调用此方法的线程在调用之前执行完毕

  ....thread1.....
  thread1.join()
  ....thread2.....

线程本来是异步的,在没加入join时候,如果两个线程同时执行是不知道两个线程执行的先后顺序的,但加入join后,join调用的线程限制性完毕后,在执行join下面的代码。
wait 与notify 区别
wait 线程休眠,释放锁,让出CPU,进入休眠
notify 唤醒休眠的线程

使用范例

while(conditioin){
  try{
    wait();
  }catch(Exception e){

  }
  .......
}

另外地方 notify() 唤醒休眠线程

线程的挂起和线程的等待的区别:

  • 线程的挂起:被动的,保护现场(页面和寄存器等),内存交出去,跟中断一样
  • 线程的等待:主动的,不需要保护线程,内存一直占用等待某种结果

锁实现同步Lock/ReentrantLock/ReadWriteLock/ReentrantReadWriteLock

  • ReentrantLock的使用
Lock lock = new ReentrantLock();
lock.lock();
...临界区...
lock.unlock();

注意:unlock解锁一定要放到try() finilly {…unlock};

  • ReentrantReadWriteLock读写锁的使用
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

//读数据时候
readWriteLock.readLock().lock();
//读临界区
readWriteLock.readLock.unlock();
....
//写数据时候
readWriteLock.writeLock().lock();
//写临界区
readWriteLock.writeLock.unlock();

读写锁和重入锁不同的是,读写锁在读的时候是运行多个线程访问资源,写时候只允许一个线程访问临界资源。

  • 锁中的多条件使用
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();

//代码执行
lock.lock();
while(条件){
  try{
    condition.await();
   }catch(Exceptioin e){
   }
}
.....//临界区代码
condition.signal();//通知唤醒休眠的线程
lock.unlock();

锁的多条件使用与前面的wait/notify类似,只是wait/notify与关键字synchroniced一起使用,而锁不需要在方法名前面添加关键字。

线程同步辅助类

  • CountDownLatch
public CountDownLatch(int count) {  };  //参数count为计数值
public void await() throws InterruptedException { };   //调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };  //和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public void countDown() { };  //将count值减1

基本工作原理:count计数值为零时候,await()被唤醒往下执行,不然一直阻塞在这里。

扫描二维码关注公众号,回复: 3194271 查看本文章
  • Semaphore
public void acquire() throws InterruptedException {  }     //获取一个许可
public void acquire(int permits) throws InterruptedException { }    //获取permits个许可
public void release() { }          //释放一个许可
public void release(int permits) { }    //释放permits个许可

基本工作原理:获取信号,相当于锁;没有获取到时候阻塞等待

  • CyclicBarier
public int await() throws InterruptedException, BrokenBarrierException { };
public int await(long timeout, TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException { };

基本工作原理:所有的线程都到达barier后开始执行

  • Exchanger 线程数据交互

    exchange(V v) //交换数据

基本工作原理:将相同的Exchanger实例在不同的线程中进行数据交换

线程池

线程池就是事先将多个线程对象放到一个容器中,当使用的时候就不用new 线程而是直接去池中拿线程即可,节省了开辟子线程的时间,提高的代码执行效率。

  1. 减少在创建和销毁线程上所花的时间以及系统资源的开销
  2. 如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存以及”过度切换
Java四种线程池使用方法
  • 4.1 newCachedThreadPool
    创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
ExecutorService executorService = Executors.newCachedThreadPool();
    executorService.execute(new Runnable() {
         @Override
         public void run() {

         }
});
  • 4.2 newFixedThreadPool
    创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
ExecutorService executorService1 = Executors.newFixedThreadPool(3);
    executorService1.execute(new Runnable() {
          @Override
          public void run() {

          }
});
  • 4.3 newScheduledThreadPool
    创建一个定长线程池,支持定时及周期性任务执行
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
    scheduledExecutorService.schedule(new Runnable() {
         @Override
         public void run() {

         }
}, 3, TimeUnit.MINUTES);
  • 4.4 newSingleThreadExecutor
    创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
ExecutorService executorService2 = Executors.newSingleThreadExecutor();
    executorService2.execute(new Runnable() {
          @Override
          public void run() {

          }
});

Fork/Join框架

分解合并框架,通过分治技术将问题按照一定的规则拆分成很多小问题来处理。

主要编程步骤:

XXXTask xxxTask = new XXXTask();
ForkJoinPool pool = new ForkJoinPool();
pool.execute(xxxTask);

XXXTask这里分为两种情况:
无返回参数的:

class XXXTask extends RecursiveAction  //(RecursiveAction extends ForkJoinTask<Void>)
//然后到实现compute方法,进行分治逻辑处理

有参数的:

class XXXTask extends RecursiveTask<T> //(RecursiveTask<T> extends ForkJoinTask<T>)
//然后到实现compute方法,进行分治逻辑处理,记得返回参数合并问题。直接可以通过task.get()方法拿到返回值。

猜你喜欢

转载自blog.csdn.net/zgkxzx/article/details/80964173