栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

并发编程笔记

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

并发编程笔记

并发编程
  • 内容概述
    • 1 并发编程基础
      • 1.1 创建线程
        • 1.1.1 继承Thread类
        • 1.1.2 实现Runnable接口,重写run方法
        • 1.1.3 匿名内部类
      • 1.2 多线程五个状态
      • 1.3 守护线程
      • 1.4 join()方法
    • 2 线程安全
      • 2.1 什么是线程安全

内容概述

什么是多线程、同步异步概念、线程安全(线程之间同步)、线程之间的通讯、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方法
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()或者穿线锁阻塞状态,执行完毕后回到就绪状态。
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线程结束-----");
    }
}

2 线程安全

分布式锁:内置锁、显示锁
内置锁(互斥锁):synchronized
显示锁:Lock

线程同步,注意死锁(例如:同步嵌套同步)
threwLocal:为线程提供局部变量
三大特性:原子性、可见性、有序性(代码执行顺序,多线程中jvm重排序)
JVM内存模型

volatilc作用:保证可见性,但不能保证原子性,在多线程并发时禁止重排序。
synchronized:保证可见性、原子性,有阻塞问题。

重排序:CPU会对代码进行优化,但不会对有依赖关系的做重排序。多线程的情况下遇到。
数据依赖关系:例 int a = 1; int b = 2; int c = a*b; a、b没有依赖关系,但c是有依赖关系的。CPU做代码优化的时候,可能会修改a/b的执行顺序。

as-if-serial语义:不管如何做重排序,提高并行度,且不影响执行结果。

public class ThreadDemo1 {
    volatile int a = 0; //volatile 禁止重排序
    volatile boolean flag = false; //volatile 禁止重排序

    //写入线程
    public void writer(){
        a = 1;
        flag = true;
    }

    
    public void reader() {
        if(flag){
            int i = a*a;
            System.out.println(i);
        }
    }

}
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,同步范围越小越好。

    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)使用的是当前字节码文件。

  2. 同步代码块
    synchronized(全局对象){}
    // 全局变量可以作为锁,各个线程用的锁要是一个

synchronized底层实现原理: //TODO

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/445527.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号