内容概述
什么是多线程、同步异步概念、线程安全(线程之间同步)、线程之间的通讯、JDK1.8并发包、线程池原理分析、锁
1、线程:一条执行路径,互不干扰。
分为:用户线程、守护线程。
也可分为:主线程、子线程、GC线程。在一个进程中,一定会有主线程。
2、多线程:在一个进程中,有多条执行路径同时执行,为了提高效率
1 并发编程基础
1.1 创建线程
1.1.1 继承Thread类
继承Thread,重写run方法
public class ThreadDemo01 extends Thread{
public static void main(String arg[]){
System.out.println("-----主线程开始-----");
//创建线程
ThreadDemo01 threadDemo01 = new ThreadDemo01 ();
//启动线程
threadDemo01.start();
for(int i = 10; i > 0; i--){
System.out.println("主线程" + i);
}
System.out.println("-----主线程结束-----");
}
@Override
public void run() {
for(int i = 10; i > 0; i--){
System.out.println("子线程" + i);
}
}
}
1.1.2 实现Runnable接口,重写run方法
/**
* 实现Runnable接口,重写run方法
*/
public class ThreadDemo02 implements Runnable{
public static void main(String arg[]){
System.out.println("-----主线程开始-----");
//创建线程
ThreadDemo02 threadDemo02 = new ThreadDemo02 ();
//启动线程
Thread t = new Thread(threadDemo02);
t.start();
for(int i = 10; i > 0; i--){
System.out.println("主线程" + i);
}
System.out.println("-----主线程结束-----");
}
@Override
public void run() {
for(int i = 10; i > 0; i--){
System.out.println("子线程" + i);
}
}
}
1.1.3 匿名内部类
public class ThreadDemo03 {
public static void main(String[] args) {
System.out.println("-----主线程开始-----");
new Thread(new Runnable(){
@Override
public void run() {
for(int i = 10; i > 0; i--){
System.out.println("子线程" + i);
}
}
}).start();
for(int i = 10; i > 0; i--){
System.out.println("主线程" + i);
}
System.out.println("-----主线程结束-----");
}
}
1.2 多线程五个状态
- 新建状态:new Thread()
- 就绪状态:等待CPU分配内存并执行
- 运行状态:执行run()
- 死亡状态:run()执行完毕
- 阻塞状态:run()方法中调用了wait()、sleep()或者穿线锁阻塞状态,执行完毕后回到就绪状态。
1.3 守护线程
- 主线程:一个进程有且只有一个主线程。
- 用户线程:用户创建的线程,非守护线程。如果主线程执行完毕,不会影响用户线程。
- GC线程:不定时回收堆中的垃圾,守护线程,和主线程一起销毁。
守护线程就是和主线程一起销毁。
public class TreadDemo implements Runnable{
public static void main(String arg[]){
System.out.println("-----主线程开始-----");
//创建线程
TreadDemo treadDemo = new TreadDemo();
//启动线程
Thread t = new Thread(treadDemo);
t.setDaemon(true); //设置为守护线程
t.start();
for(int i = 100; i > 0; i--){
System.out.println("主线程" + i);
}
System.out.println("-----主线程结束-----");
}
@Override
public void run() {
for(int i = 100; i > 0; i--){
System.out.println("子线程" + i);
}
}
}
1.4 join()方法
A线程执行过程中,调用B线程的join方法,A会等待join执行完毕后,再继续执行。
join()方法就是释放别的线程的CPU执行权,给join。
public class TreadDemo{
public static void main(String arg[]){
System.out.println("-----主线程开始-----");
//启动线程
Thread t = new Thread(new Runnable() {
@Override
public void run() {
for(int i = 10; i > 0; i--){
System.out.println("子线程" + i);
}
}
});
t.start();
try {
t.join(); //将CPU的执行权让给子线程
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i = 10; i > 0; i--){
System.out.println("主线程" + i);
}
System.out.println("-----主线程结束-----");
}
}
题:现在又T1、T2、T3三个线程中如何保证T2在T1执行完毕之后执行,T3在T2执行完毕之后执行?
public class TreadDemo{
public static void main(String arg[]){
System.out.println("-----T3线程开始-----");
//启动线程
Thread T2 = new Thread(new Runnable() {
@Override
public void run() {
//启动线程
Thread T1 = new Thread(new Runnable() {
@Override
public void run() {
for(int i = 3; i > 0; i--){
System.out.println("T1线程" + i);
}
}
});
T1.start();
try {
T1.join(); //将CPU的执行权让给子线程
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i = 3; i > 0; i--){
System.out.println("T2线程" + i);
}
}
});
T2.start();
try {
T2.join(); //将CPU的执行权让给子线程
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i = 3; i > 0; i--){
System.out.println("T3线程" + i);
}
System.out.println("-----T3线程结束-----");
}
}
1.5 fork/join //TODO
2 线程安全
分布式锁:内置锁、显示锁
内置锁(互斥锁):synchronized
显示锁:Lock
线程同步,注意死锁(例如:同步嵌套同步)
threwLocal:为线程提供局部变量
三大特性:原子性、可见性、有序性(代码执行顺序,多线程中jmm重排序)
2.1 什么是线程安全
线程安全问题:当多个线程共享用一个全局变量,做写操作时,可能会受到其他线程的影响。读操作是不会引发线程安全问题。例如,多窗口卖火车票。
public class ThreadDemo1 implements Runnable {
//多个窗口同时卖100张火车票
private static int count = 100;
@Override
public void run() {
while (count > 0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
sale();
}
}
private void sale() {
if (count > 0) {
System.out.println(Thread.currentThread().getName() + ":正在出售第" + (100 - count + 1) + "张火车票");
count--;
}
}
public static void main(String[] arg) {
ThreadDemo1 td = new ThreadDemo1();
Thread t1 = new Thread(td, "线程1");
Thread t2 = new Thread(td, "线程2");
t1.start();
t2.start();
}
}
解决方法,在操作共享参数的方法加synchronized,同步范围越小越好。
//非静态同步方法,锁是this(对象本身)
private synchronized void sale(){
if(count > 0){
System.out.println(Thread.currentThread().getName() + ":正在出售第"+(100-count+1) + "张火车票");
count--;
}
}
synchronized,悲观锁,保证线程原子性。当线程进入方法的时候,自动获取锁,其他线程等待。当线程执行完毕后释放锁,降低程序的运行效率。
使用方法:同步方法、同步代码块。
- 同步方法:修饰在方法上,见上述例子–private synchronized void sale()
非静态同步方法使用的锁是this(对象本身),
静态同步方法(static)使用的是当前文件的字节码文件(.class),将会锁住整个类。
//静态同步方法,锁用的是当前文件的字节码文件(.class)
private static synchronized void sale(){
if(count > 0){
System.out.println<