1 并发编程的基础(实现/生命周期)
public class MyThread extends Thread {
public void run() {
System.out.println("MyThread.run()");
}
}
MyThread myThread1 = new MyThread();
MyThread myThread2 = new MyThread();
myThread1.start();
myThread2.start();
继承Thread类创建线程类
01. 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体。
public class MyThread extends Thread{
02. 创建Thread子类的实例,即创建了线程对象。
MyThread t1=new MyThread();
03. 调用线程对象的start()方法来启动该线程。
t1.start();
public class MyThread extends OtherClass implements Runnable { public void run() { System.out.println("MyThread.run()"); } }
实现Runnable接口创建线程类
01. 定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
public class MyThread1 implements Runnable{
02. 创建Runnable实现类的实例,并以此实例(mt)作为Thread的target来创建Thread对象(t1),该Thread对象才是真正的线程对象。
MyThread1 mt=new MyThread1();
// 启动3个线程t1,t2,t3(它们共用一个Runnable对象),这3个线程一共卖10张票!
Thread t1=new Thread(mt);
03. 调用线程对象的start()方法来启动线程。
需要注意的是:Runnable对象仅仅作为Thread对象的target,Runnable实现类里包含的run()方法仅作为线程执行体。而实际的线程对象依然是Thread实例,只是该Thread线程负责执行其target的run()方法。
t1.start();
3 使用 ExecutorService、Callable、Future 实现带返回结果的多线程。
public class CallableDemo implements Callable<String> { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool(1); CallableDemo callableDemo = new CallableDemo(); Future<String> future = executorService.submit(callableDemo); System.out.println(future.get()); executorService.shutdown(); } @Override public String call() throws Exception { int a = 1; int b = 2; System.out.println(a + b); return "执行结果:" + (a + b); } }
Java线程具有五种基本状态
1、新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();
2、就绪状态(Runnable):也被称为“可执行状态”。当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
3、运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
4、阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:
(1)等待阻塞 -- 运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
(2)同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;
(3)其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

代码显示线程的状态
package com.gupaoedu.vip; import java.util.concurrent.TimeUnit; public class ThreadStatusDemo { public static void main(String[] args) { new Thread(()->{ while(true){ try { TimeUnit.SECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } },"Time_Waiting_Thread").start(); new Thread(()->{ while(true){ synchronized (ThreadStatusDemo.class) { try { ThreadStatusDemo.class.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } },"Wating_Thread").start(); //BLOCKED new Thread(new BlockedDemo(),"Blocke01_Thread").start(); new Thread(new BlockedDemo(),"Blocke02_Thread").start(); } static class BlockedDemo extends Thread{ @Override public void run() { synchronized (BlockedDemo.class){ while(true){ try { TimeUnit.SECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }
E:\GUPAO\FILE\VIP专享--2019期录播视频及资料\03.分布式与高并发\01.分布式并发编程\01.初步认识多线程的发展及使用\课堂源码\20190509-并发编程第一次课源码\thread-demo\target\classes\com\gupaoe du\vip>jps 5152 Launcher 5168 ThreadStatusDemo 5364 5476 Jps 5688 App 7160 KotlinCompileDaemon 6108 RemoteMavenServer36 E:\GUPAO\FILE\VIP专享--2019期录播视频及资料\03.分布式与高并发\01.分布式并发编程\01.初步认识多线程的发展及使用\课堂源码\20190509-并发编程第一次课源码\thread-demo\target\classes\com\gupaoe du\vip>jstack 5168 2020-02-01 21:47:57 Full thread dump Java HotSpot(TM) Client VM (25.144-b01 mixed mode): "DestroyJavaVM" #15 prio=5 os_prio=0 tid=0x14dd5c00 nid=0x1bb4 waiting on condition [0x00000000] java.lang.Thread.State: RUNNABLE "Blocke02_Thread" #14 prio=5 os_prio=0 tid=0x14dd5800 nid=0x8a8 waiting for monitor entry [0x14f7f000] java.lang.Thread.State: BLOCKED (on object monitor) at com.gupaoedu.vip.ThreadStatusDemo$BlockedDemo.run(ThreadStatusDemo.java:46) - waiting to lock <0x04bbf470> (a java.lang.Class for com.gupaoedu.vip.ThreadStatusDemo$BlockedDemo) at java.lang.Thread.run(Thread.java:748) "Blocke01_Thread" #12 prio=5 os_prio=0 tid=0x14dd5000 nid=0x16cc waiting on condition [0x1565f000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at java.lang.Thread.sleep(Thread.java:340) at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386) at com.gupaoedu.vip.ThreadStatusDemo$BlockedDemo.run(ThreadStatusDemo.java:46) - locked <0x04bbf470> (a java.lang.Class for com.gupaoedu.vip.ThreadStatusDemo$BlockedDemo) at java.lang.Thread.run(Thread.java:748) "Wating_Thread" #10 prio=5 os_prio=0 tid=0x14dd4800 nid=0x1f34 in Object.wait() [0x1589f000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x04a00390> (a java.lang.Class for com.gupaoedu.vip.ThreadStatusDemo) at java.lang.Object.wait(Object.java:502) at com.gupaoedu.vip.ThreadStatusDemo.lambda$main$1(ThreadStatusDemo.java:27) - locked <0x04a00390> (a java.lang.Class for com.gupaoedu.vip.ThreadStatusDemo) at com.gupaoedu.vip.ThreadStatusDemo$$Lambda$2/23237446.run(Unknown Source) at java.lang.Thread.run(Thread.java:748) "Time_Waiting_Thread" #9 prio=5 os_prio=0 tid=0x14dd3400 nid=0x15b4 waiting on condition [0x1575f000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at java.lang.Thread.sleep(Thread.java:340) at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386) at com.gupaoedu.vip.ThreadStatusDemo.lambda$main$0(ThreadStatusDemo.java:16) at com.gupaoedu.vip.ThreadStatusDemo$$Lambda$1/24037599.run(Unknown Source) at java.lang.Thread.run(Thread.java:748) "Service Thread" #8 daemon prio=9 os_prio=0 tid=0x14d06800 nid=0x18cc runnable [0x00000000] java.lang.Thread.State: RUNNABLE "C1 CompilerThread0" #7 daemon prio=9 os_prio=2 tid=0x14d07800 nid=0x1c20 waiting on condition [0x00000000] java.lang.Thread.State: RUNNABLE "Monitor Ctrl-Break" #6 daemon prio=5 os_prio=0 tid=0x14ce8000 nid=0xa80 runnable [0x1510f000] java.lang.Thread.State: RUNNABLE at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.socketRead(SocketInputStream.java:116) at java.net.SocketInputStream.read(SocketInputStream.java:171) at java.net.SocketInputStream.read(SocketInputStream.java:141) at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284) at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326) at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178) - locked <0x049d32d0> (a java.io.InputStreamReader) at java.io.InputStreamReader.read(InputStreamReader.java:184) at java.io.BufferedReader.fill(BufferedReader.java:161) at java.io.BufferedReader.readLine(BufferedReader.java:324) - locked <0x049d32d0> (a java.io.InputStreamReader) at java.io.BufferedReader.readLine(BufferedReader.java:389) at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:64) "Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x14cd1c00 nid=0xb10 waiting on condition [0x00000000] java.lang.Thread.State: RUNNABLE "Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x14cb8800 nid=0x1044 runnable [0x00000000] java.lang.Thread.State: RUNNABLE "Finalizer" #3 daemon prio=8 os_prio=1 tid=0x14ca9c00 nid=0x18fc in Object.wait() [0x1509f000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x04807ee0> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143) - locked <0x04807ee0> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209) "Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x14c83000 nid=0x151c in Object.wait() [0x024ff000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x04805f68> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:502) at java.lang.ref.Reference.tryHandlePending(Reference.java:191) - locked <0x04805f68> (a java.lang.ref.Reference$Lock) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153) "VM Thread" os_prio=2 tid=0x14c7bc00 nid=0x1eb0 runnable "VM Periodic Task Thread" os_prio=2 tid=0x14d97800 nid=0x109c waiting on condition JNI global references: 336
package com.gupaoedu.vip; import java.util.concurrent.TimeUnit; public class InterruptDemo { private static int i; public static void main(String[] args) throws InterruptedException { Thread thread=new Thread(()->{ //如果不是中斷狀態則i++ while(!Thread.currentThread().isInterrupted()){//默认是false _interrupted state? i++; } System.out.println("i:"+i); }); thread.start(); TimeUnit.SECONDS.sleep(1); thread.interrupt(); //把isInterrupted设置成true } }
thread.interrupt();将判断标志设置成true,默认判断标志为false,然后通过两种中断方式来中断线程。
//1. Thread.interrupted() 通过复位中断异常
//2. InterruptedException 通过抛出异常中断线程
为什么要复位(设置成默认状态false)
Thread.interrupted()是属于当前线程的,是当前线程对外界中断信号的一个响应,表示自己已经得到了中断信号,但不会立刻中断自己,具体什么时候中断由自己决定,让外界知道在自身中断前,他的中断状态仍然是 false,这就是复位的原因。

多线程知识点问答
1创建线程的几种方式? Wait,sleep分别是谁的方法,区别?线程间的通信方式?
继承Thread类创建线程,实现Runnable接口创建线程,使用Callable和Future创建线程 ,使用线程池例如用Executor框架。 Wait是在Object.java中的方法,sleep是在Thread.java中的方法。 区别是wait是当前运行线程进入阻塞状态并释放锁,sleep使线程进入阻塞状态但不释放锁。 使用wait和notify实现线程间的通信。
2 介绍下什么是死锁,遇见过死锁么?你是怎么排查的?(可以通过JPS排查)
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去,通过jps排查。
3 创建线程池的几种方式,线程池有什么好处?
单线程的线程池 固定大小的线程池 一个可缓存的线程池 一个大小无限的线程池
频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。线程池可以使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务。
4 线程继承和接口的区别,接口有什么好处?
java中我们想要实现多线程常用的有两种方法,继承Thread 类和实现Runnable 接口,有经验的程序员都会
选择实现Runnable接口 ,其主要原因有以下两点:首先,java只能单继承,因此如果是采用继承Thread的方法,那么在以后进行代码重构的时候可能会遇到问题,因为你无法继承别的类了。其次,如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
5 synchronized ,lock ,reentrantlock 的区别,用法及原理
ReenTrantLock可以指定是公平锁还是非公平锁。而synchronized只能是非公平锁;ReenTrantLock提供了一个Condition(条件)类,可实现分组唤醒线程,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程;ReenTrantLock提供了一种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制。synchronized不可中断
6 countDownLatch 与 CyclicBarrier 的用法
CountDownLatch的计数器,线程完成一个记录一个,计数器是递减 计数器,只能使用一次;CyclicBarrier的计数器 更像是一个阀门,需要所有线程都到达,阀门才能打开,然后继续执行,计数器是递增 计数器提供reset功能,可以多次使用
7 ThreadLocal 的用法及原理
ThreadLocal用处就是用来把实例变量共享成全局变量,在程序的任何方法中都可以访问到该实例变量;
线程隔离的原理, ThreadLocalMap类是ThreadLocal类的一个静态内部类,它实现了键值对的设置和获取,每个线程中都有一个独立的ThreadLocalMap副本(key-ThreadLocal,value-副本),它所存储的值(副本),只能被当前线程读取和修改。ThreadLocal类通过操作每一个线程特有的ThreadLocalMap副本,从而实现了专属变量访问在不同线程中的隔离。因为每个线程的变量都是自己特有的,完全不会有并发错误。
8 volatile 关键字的作用及用法
保证内存可见性 , volatile关键字用于声明简单类型变量,如int、float、 boolean等数据类型。如果这些简单数据类型声明为volatile,对它们的操作就会变成原子级别的。
9 乐观锁和悲观锁
10 对公平锁,非公平锁,可重入锁,自旋锁,读写锁的理解
锁是基于线程的分配,可重入锁: 可以被单个线程多次获取。可中断锁: 某一线程A正在执行锁中的代码,另一线程B正在等待获取该锁,可能由于等待时间过长,线程B不想等待了,想先处理其他事情,我们可以让它中断自己或者在别的线程中中断它,种就是可中断锁。 公平锁:即尽量以请求锁的顺序来获取锁。自旋锁,一个线程A在获得普通锁后,如果再有线程B试图获取锁,那么这个线程B将会(阻塞)。读写所:读写锁将对一个资源(比如文件)的访问分成了2个锁,一个读锁和一个写锁,正因为有了读写锁,才使得多个线程之间的读操作不会发生冲突。
11 CAS是什么及底层原理
CAS是一条CPU并发原语。判断内存某个位置的值是否为预期值,如果是更改为新值,这个过程是原子的。
底层原理:Unsafe类是CAS的核心类,由于java方法无法直接访问底层系统,需要通过本地(native)方法来访问,基于该类可以直接操作特定内存的数据。Unsafe类中的所有方法都是native修饰的,也就是说Unsafe类中的方法都直接调用操作系统底层资源执行相应任务
12 ArrayBlockingQueue,LinkedBlockQueue,SynchronousQueue等等堵塞队列的理解
SynchronousQueue是无界的,是一种无缓冲的等待队列,但是由于该Queue本身的特性,在某次添加元素后必须等待其他线程取走后才能继续添加;可以认为SynchronousQueue是一个缓存值为1的阻塞队列
LinkedBlockingQueue是无界的,是一个无界缓存的等待队列。当队列缓冲区达到最大值缓存容量时,才会阻塞生产者队列,直到消费者从队列中消费掉一份数据,生产者线程会被唤醒,反之对于消费者这端的处理也基于同样的原理。
在高并发的情况下生产者和消费者可以并行地操作队列中的数据,以此来提高整个队列的并发性能。
ArrayBlockingQueue是有界的,是一个有界缓存的等待队列。在生产者放入数据和消费者获取数据,都是共用同一个锁对象,由此也意味着两者无法真正并行运行,这点尤其不同于LinkedBlockingQueue;ArrayBlockingQueue和LinkedBlockingQueue是两个最普通、最常用的阻塞队列,一般情况下,处理多线程间的生产者消费者问题,使用这两个类足以。
13 ThreadPoolExecutor 的传入参数及内部工作原理
14 给你一个具体的业务场景,让你使用ThreadPoolExecutor 创建一个合适的线程池
15 分布式环境下怎么保证线程安全。

浙公网安备 33010602011771号