一、创建线程方式
- 继承Thread类创建线程类
- 通过Runnable接口创建线程类
- 通过Callable和Future创建线程
二、关于start、Run线程区别
线程的启动方式只能通过start这种方式启动才能真正的实现多线程的效果,如果是手动调用run方法和普通方法调用没有区别
三、流程图
四、sleep() 、wait() 等方法
1.sleep()方法
-
在指定时间内让当前正在执行的线程暂停执行,但不会释放“锁标志”。不推荐使用。
-
sleep()使当前线程进入阻塞状态,在指定时间内不会执行。
-
(休眠)是线程类(Thread)的静态方法,调用此方法让当前线程暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复
2.wait()方法
-
在其他线程调用对象的notify或notifyAll方法前,导致当前线程等待。线程会释放掉它所占有的“锁标志”,从而使别的线程有机会抢占该锁。
-
当前线程必须拥有当前对象锁。如果当前线程不是此锁的拥有者,会抛出IllegalMonitorStateException异常。
-
唤醒当前对象锁的等待线程使用notify或notifyAll方法,也必须拥有相同的对象锁,否则也会抛出IllegalMonitorStateException异常。
-
waite()和notify()必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized函数或non-synchronized block中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常。
-
是Object类的方法,调用对象的wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的notify()方法(或notifyAll()方法)时才能唤醒等待池中的线程进入等锁池(lock pool),如果线程重新获得对象的锁就可以进入就绪状态。
3.yield方法
-
暂停当前正在执行的线程对象。
-
yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。
-
yield()只能使同优先级或更高优先级的线程有执行的机会。
4.join方法
- join()等待该线程终止。
- 等待调用join方法的线程结束,再继续执行。如:t.join();//主要用于等待t线程运行结束,若无此句,main则会执行完毕,导致结果不可预测
五、用户线程(user-level threads)
用户线程(user-level threads) 指不需要内核支持而在用户程序中实现的线程,其不依赖于操作系统核心,应用进程利用线程库提供创建、同步、调度和管理线程的函数来控制用户线程。
六、ThreadLocal
-
ThreadLocal是采用哈希表的方式来为每个线程都提供一个变量的副本
-
ThreadLocal保证各个线程间数据安全,每个线程的数据不会被另外线程访问和破坏
七、InterruptedException抛出
-
java.lang.Object 类的 wait 方法
-
java.lang.Thread 类的 sleep 方法
-
java.lang.Thread 类的 join 方法
八、volatile
一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
2)禁止进行指令重排序。
volatile只提供了保证访问该变量时,每次都是从内存中读取最新值,并不会使用寄存器缓存该值——每次都会从内存中读取。
而对该变量的修改,volatile并不提供原子性的保证。
由于及时更新,很可能导致另一线程访问最新变量值,无法跳出循环的情况
多线程下计数器必须使用锁保护。
九、线程共享
方法区和堆内存是线程共享的。
程序计数器、虚拟机栈是线程隔离的。