关于java:简单的聊一聊创建线程的三种方式以及常用线程池介绍

35次阅读

共计 4812 个字符,预计需要花费 13 分钟才能阅读完成。

过程和线程

~ 线程是在一个过程中,并发执行的多个程序逻辑,线程是过程执行的单位。
~ 一个过程中至多有一个线程,而这个线程被称为主线程,主线程是一个程序的入口,main 就是由主线程来执行的。
 

线程创立三种形式:

1. 继承 Thread 类
2. 实现 Rnnable 接口
3. 实现 Callable 接口  

继承 Thread

public class thread extends Thread{
 
    @Override
    public void run() {for (int i = 0; i < 20; i++) {System.out.println("这是 run 线程"+i);
        }
    }
    
    public static void main(String[] args) {
 
        // 开启 run 线程 start 是同时运行 run 办法是先执行 run 办法 在执行主线程
        thread thread = new thread();
        thread.start();// 开启线程
        for (int i = 0; i < 200; i++) {System.out.println("这是 main 线程"+i);
        }
    }
}

 

实现 Rnnable 接口

public class runnable implements Runnable{
    @Override
    public void run() {for (int i = 0; i < 20; i++) {System.out.println("这是 run 线程"+i);
        }
    }
    
    public static void main(String[] args) {runnable runnable = new runnable();// 创立线程对象
        new Thread(runnable,"定义线程名").start();// 须要一个 Thread 对象
        for (int i = 0; i < 200; i++) {System.out.println("这是 main 线程"+i);
        }
    }
}

 

实现 Callable 接口

public class callable implements Callable<Object> {
 
 
    @Override
    public Object call() throws Exception {Object object = new Object();
        return object;
    }
 
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创立线程
        callable callable = new callable();
        // 创立执行服务
        ExecutorService pool = Executors.newFixedThreadPool(3);
        // 执行线程 获取后果
        Future<Object> res = pool.submit(callable);
        Object obj = res.get();
        // 敞开服务
        pool.shutdownNow();}
}

~ run 办法和 start 办法两者是有区别的,run 会先运行 run 里代码在运行主线程,start 是同时运行。

~ 线程开启并不一定立刻执行,是由 cpu 调度的,人为无奈干涉。

~ 获取以后线程的名字

Thread.currentThread().getName();

 ~ 获取线程的状态

State state = thread.getState();

线程的五种状态

  • 初始状态 new 当创立了一个线程时,会进入此状态。
  • 就绪状态 当初始状态调用了 start()办法时,会进入此状态。
  • 运行状态 当就绪状态的线程取得 cpu 工夫片,即调度到它,进入运行状态。
  • 梗塞状态 当调用 sleep,wait 办法或同步锁定,线程进入梗塞,代码不往下执行,梗塞事件完结后从新进入 * 就绪状态,期待 cpu 调度。

终止状态 线程中断或者执行完所有代码,进入终止状态。

synchronized 隐式锁

synchronize 有两种时用,同步办法,同步代码块。synchronize 同步办法默认锁的时 this,即以后对象,同步代码块能够锁任何对象。死锁线程单方锁了对方所须要的临界资源,导致单方都处于梗塞状态。

同步代码块:

        synchronized (obj){//obj 须要锁的对象}

lock 显示锁

不同于 synchronize(修饰符),lock 是可重入锁,是一个对象,他只能锁代码块,由 jdk1.5 推出的新个性,lock 已本身为标记,代替了临界资源互斥锁标记。

创立 lock 锁:

 private final ReentrantLock lock = new ReentrantLock(); // 创立 lock 锁对象

 try{lock.lock(); // 加锁
    ...
 }finally{lock.unlock(); // 解锁
 }

线程之间的通信

~ 线程间的通信 须要临界资源来调用相应的办法 因为锁标记是临界资源所领有的
 
wait():当临界资源调用 wait() 办法时 以后线程 放弃工夫片 放弃互斥锁标记 进入期待区(进入阻塞状态) 

notify():当临界资源调用 notify()时会依据肯定策略 唤醒期待区中的某个线程 该线程从新回归就绪状态

notifyAll():当临界资源调用 notifyAll()时 唤醒期待区中的所有线程 所有线程进入就绪状态

 

sleep()和 wait()区别

它俩来自不同的类,sleep()是 Thread 类的,wait()是来自于 Object 类。
sleep() 只让出了 CPU,却不会开释对象锁,处于梗塞状态,它须要设置休眠工夫。wait()会放弃对象锁,并让出 cpu 资源,处于期待状态,应用 notify()和 notifyAll()来唤醒。
sleep() 会抛出 InterruptedException 异样,须要进行相干解决,而 wait()不须要捕捉异样。
 

线程平安的汇合

CopyOnWriteArrayList:所在包 java . util . concurrent;读操作远远大于写操作时,效率高,在写时会先创立正本将写操作进行结束时,再替换原容器,保障读的正确性,但写的效率很低。
 
ConcurrentHashMap : 所在包 java . util . concurrent;进步了 HashMap 的并发效率,应用了分级锁,将本来的 hash 表分,成了 16 段,一个 hash 表时,有一个线程操作任意一个地位,都会导致 hash 被锁,但分成了 16 段加锁时,一个线程拜访一部分时,其余线程能够拜访其余局部。
 
 
 

线程池

~ 顾名思义,一个池子用来装线程的容器,可已设定线程调配数量下限,将事后创立线程对象存入池中,并重用线程池中的线程。

~ 益处是缩小创立和销毁线程的次数。

线程池的根本接口:Executor

线程池接口:ExecutorService

线程池工具类:Executors,用于创立线程。

newSingleThreadPool 创立一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有工作。如果这个惟一的线程因为异样完结,那么会有一个新的线程来代替它,此线程池保障所有工作的执行程序依照工作的提交程序执行。

   public class ThreadPoolExecutorTest {public static void main(String[] args) {ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
           for (int i = 0; i < 10; i++) {
               final int index = i;
               singleThreadExecutor.execute(new Runnable() {public void run() {
                       try {System.out.println(index);
                           Thread.sleep(2000);
                       } catch (InterruptedException e) {e.printStackTrace();
                       }
                   }
               });
           }
       }
   }

 

newFixedThreadPool 创立固定大小的线程池。每次提交一个工作就创立一个线程,直到线程达到线程池的最大大小。某个线程因为执行异样而完结,那么线程池会补充一个新线程。

   public class ThreadPoolExecutorTest {public static void main(String[] args) {ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
           for (int i = 0; i < 10; i++) {
               final int index = i;
               fixedThreadPool.execute(new Runnable() {public void run() {
                       try {System.out.println(index);
                           Thread.sleep(2000);
                       } catch (InterruptedException e) {e.printStackTrace();
                       }
                   }
               });
           }
       }
   }

newCachedThreadPool 创立一个可缓存的线程池。如果线程池的大小超过了解决工作所须要的线程,那么就会回收局部变量(60 秒不执行工作)的线程,当工作数减少时,此线程池又能够智能的增加新线程来解决工作。此线程池不会对线程池大小做限度,线程池大小齐全依赖于操作系统(或者说 JVM)可能创立的最大线程大小。

    public class ThreadPoolExecutorTest {public static void main(String[] args) {ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
            for (int i = 0; i < 10; i++) {
                final int index = i;
                try {Thread.sleep(index * 1000);
                } catch (InterruptedException e) {e.printStackTrace();
                }
                cachedThreadPool.execute(new Runnable() {public void run() {System.out.println(index);
                    }
                });
            }
        }
    }

newScheduledThreadPool 创立一个定长的线程池,而且反对定时的以及周期性的工作执行,反对定时及周期性工作执行。

    public class ThreadPoolExecutorTest {public static void main(String[] args) {ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
            scheduledThreadPool.schedule(new Runnable() {public void run() {System.out.println("delay 3 seconds");
                }
            }, 3, TimeUnit.SECONDS);
        }
    }

 

应用

public static void main(String[] args) {
        // 创立线程工作对象
        MyRunnable02 mr=new MyRunnable02();
        // 获取线程池对象
        ExecutorService es=Executors.newFixedThreadPool(2);
        // 调用办法执行线程工作
        es.submit(mr);
        es.submit(mr);
        // 销毁线程池
        es.shutdown();}

最初

欢送关注公众号:前程有光,支付一线大厂 Java 面试题总结 + 各知识点学习思维导 + 一份 300 页 pdf 文档的 Java 外围知识点总结!这些材料的内容都是面试时面试官必问的知识点,篇章包含了很多知识点,其中包含了有基础知识、Java 汇合、JVM、多线程并发、spring 原理、微服务、Netty 与 RPC、Kafka、日记、设计模式、Java 算法、数据库、Zookeeper、分布式缓存、数据结构等等。

正文完
 0