并发编程笔记

本文详细介绍了Java并发编程的基础知识,包括线程的创建、状态、守护线程和join()方法,以及线程安全问题、Java内存模型、volatile关键字、线程间通信、线程池原理、锁机制(如重入锁、读写锁、乐观锁和悲观锁)等。通过实例分析,阐述了如何避免死锁、使用ThreadLocal和线程池,并探讨了并发工具如阻塞队列和Fork/Join框架。文章最后讨论了自旋锁、公平与非公平锁以及分布式锁的概念。
摘要由CSDN通过智能技术生成

内容概述

什么是多线程、同步异步概念、线程安全(线程之间同步)、线程之间的通讯、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 多线程五个状态

  1. 新建状态:new Thread()
  2. 就绪状态:等待CPU分配内存并执行
  3. 运行状态:执行run()
  4. 死亡状态:run()执行完毕
  5. 阻塞状态:run()方法中调用了wait()、sleep()或者穿线锁阻塞状态,执行完毕后回到就绪状态。
start
run
run执行完毕
wait/sleep
wait/sleep运行完毕
新建 new Thread
就绪
执行
死亡
阻塞

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,悲观锁,保证线程原子性。当线程进入方法的时候,自动获取锁,其他线程等待。当线程执行完毕后释放锁,降低程序的运行效率。
使用方法:同步方法、同步代码块。

  1. 同步方法:修饰在方法上,见上述例子–private synchronized void sale()
    非静态同步方法使用的锁是this(对象本身),
    静态同步方法(static)使用的是当前文件的字节码文件(.class),将会锁住整个类。
	//静态同步方法,锁用的是当前文件的字节码文件(.class)
    private static synchronized void sale(){
   
        if(count > 0){
   
            System.out.println<
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值