什么是并发

  • 并发是程序同时处理多个任务的能力
  • 并发编程的根源是在于对多任务情况下对访问自由的有效控制

基本概念

  • 进程

    • 进程进程之间是相互隔离的,互不干扰
    • 计算机资源分配的基本单位
  • 线程

    • 线程是进程内的一个基本任务,每个线程都有自己的功能
    • 是CPU调度的基本单位
  • 并行

    • 多核CPU
    • 两个任务同时执行的
    • image-20230203141003980
  • 并发

    • 单核CPU的时间片轮转
    • image-20230203141014623
  • 同步

  • 异步

    • 无需等待,等处理完毕之后通知
  • 临界区

    • 表示可以被多个线程访问的共享资源
    • 同一时间之内有一个线程访问临界区
  • 死锁

    • 多个进程争夺临界资源造成的互相僵持的状态
  • 饥饿

    • 饥饿指的是某一线程或多个线程因为某些原因一直获取不到资源
  • 活锁

    • 资源没有被占用、多个线程还都在等待
  • 线程安全

    • 在拥有共享数据的多条线程并行执行的程序中,各个线程都可以争取的执行,不会出现数据污染的情况

Java内存模型

image-20230203221532256

image-20230203223749042

创建线程方式

继承Thread类创建线程

public class Match1 {
    public static void main(String[] args) {
        Runner runner1 = new Runner();
        runner1.setName("跑者A");

        Runner runner2 = new Runner();
        runner2.setName("跑者B");
        runner1.start();
        runner2.start();
    }

}

class Runner extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(this.getName() + i);
        }
    }
}

几个进程:

  • 四个,X、Y、主进程、垃圾回收进程

实现Runnable接口创建线程

public class Match1 {
    public static void main(String[] args) {
        Thread thread1 = new Thread(new Runner());
        thread1.setName("跑者A");
        Thread thread2 = new Thread(new Runner());
        thread2.setName("跑者B");
        
        thread1.start();
        thread2.start();
    }

}

class Runner implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "跑了" + i + "米");
        }
    }
}

实现Callable接口

public class Match1 {
    public static void main(String[] args) {
        Runner runner1 = new Runner();
        runner1.setName("跑者1");
        Runner runner2 = new Runner();
        runner2.setName("跑者2");


        ExecutorService executorService = Executors.newFixedThreadPool(2);
        Future<Integer> result1 = executorService.submit(runner1);
        Future<Integer> result2 = executorService.submit(runner2);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        executorService.shutdown();
    }

}

class Runner implements Callable<Integer> {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public Integer call() {
        for (int i = 0; i < 100; i++) {
            System.out.println(this.getName() + "跑了" + i + "米");
        }
        return null;
    }
}

优缺点

继承Thread实现Runnable利用线程池
优点编程简单,执行效率高面向接口编程,破除单继承的影响;执行效率高容器管理线程;允许返回值和异常
缺点单继承限制,无法有效对线程组控制无法有效控制线程组;无异常和返回值执行效率低,编程麻烦
使用场景不推荐简单的多线程企业级应用

Synchronized线程同步机制

image-20230204214626713

image-20230204215418630

测试StringBuilder和StringBuffer线程安全

// StringBuffer是线程安全的
public class Main {
    public static void main(String[] args) throws InterruptedException {
        StringBuffer stringBuffer = new StringBuffer();
        StringTest stringTest = new StringTest();
        stringTest.setStringBuffer(stringBuffer);

        Thread t1 = new Thread(stringTest);
        Thread t2 = new Thread(stringTest);
        t1.start();
        t2.start();
        Thread.sleep(100);
        System.out.println(stringTest.getStringBuffer().length());
    }
}


class StringTest implements Runnable {
    private StringBuffer stringBuffer;

    public StringBuffer getStringBuffer() {
        return stringBuffer;
    }

    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            stringBuffer.append('a');
        }
    }

    public void setStringBuffer(StringBuffer stringBuffer) {
        this.stringBuffer = stringBuffer;
    }
}
//StringBuilder是线程不安全的
public class Main {
    public static void main(String[] args) throws InterruptedException {
        StringBuilder stringBuilder = new StringBuilder();
        StringTest stringTest = new StringTest();
        stringTest.setStringBuilder(stringBuilder);

        Thread t1 = new Thread(stringTest);
        Thread t2 = new Thread(stringTest);
        t1.start();
        t2.start();
        Thread.sleep(1000);
        System.out.println(stringTest.getStringBuilder().length());
    }
}

class StringTest implements Runnable {
    private StringBuilder stringBuilder;


    public StringBuilder getStringBuilder() {
        return stringBuilder;
    }

    public void setStringBuilder(StringBuilder stringBuilder) {
        this.stringBuilder = stringBuilder;
    }

    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            stringBuilder.append('a');
        }
    }
}
最后修改:2023 年 02 月 04 日
如果觉得我的文章对你有用,请随意赞赏