Java教程

java多线程编程

本文主要是介绍java多线程编程,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

多线程简介

对多线程的理解

1. 多任务与多线程

   多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销。

2. 多线程例子(生活,游戏,编程)

  1. 边吃饭边玩手机,边听歌边写作业

  2. 开黑打游戏

  3. 等等

3. 进程,程序,线程的理解

  • 进程: 是程序的一次执行,是动态的,一个进程至少包含一个线程,一个线程不能独立存在,它必须是进程的一部分;一个进程一直运行,直到所有非守护线程都结束运行后才能结束。

  • 程序是代码段,是静态的。

  • 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。线程是一个动态执行的过程,它也有一个从产生到死亡的过程。

3. 核心概念

  • 线程是独立的执行路径;

  • 在程序运行时,即使没有自己的创建的线程,后台也会有多个线程,如主线程,gc线程;

  • main()为主线程,是程序的入口,用于执行整个程序;

  • 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器由操作系统的调度算法决定,人为不可干涉;

  • 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;

  • 线程会带来额外的开销,如CPU调度的时间,并发控制的开销;

  • 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致;

线程实现

线程的优先级

   每一个 Java 线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。

创建线程

  1. 通过继承Thread类线程创建线程
public class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("MyThread is running!!! " + i);
        }
    }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();


        for (int i = 0; i < 1000; i++) {
            System.out.println("Main Thread is running " + i);
        }
    }
}
  1. 通过实现Runnable接口创建线程
public class RunnableDemo {
    public static void main(String[] args) {
        MyRunnable R1 = new MyRunnable("Thread-1");
        R1.start();

        MyRunnable R2 = new MyRunnable("Thread-2");
        R2.start();
        
        for (int i = 0; i < 3 ; i++) {
            System.out.println("这是主线程main");
        }
    }
}


class MyRunnable implements Runnable {
    private Thread t;
    private String threadName;

    public MyRunnable(String name) {
        threadName = name;
        System.out.println("Creating: " + threadName);
    }

    @Override
    public void run()  {
        System.out.println("Running: " + threadName );
        try {
            for (int i = 4; i > 0; i--) {
                System.out.println("Thread: " + threadName + "," + i);
                Thread.sleep(50);
            }
        } catch (InterruptedException e) {
            System.out.println("Thread: " + threadName + "interrupted.");
        }
        System.out.println("Thread " + threadName + " exiting.");
    }

    public void start() {
        System.out.println("Starting " + threadName);
        if (t == null) {
            t = new Thread(this, threadName);
            t.start();
        }
    }
}
  1. 通过Callable接口创建线程

静态代理

  • 真实对象和代理对象都要实现同一个接口
  • 代理对象要代理真实对象
  • 优点:
    • 代理对象可以做很多真实对象做不了的事情
    • 真实对象专注于自己的事情

线程状态

  • 线程的生命周期

1. 新建状态

   使用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序star()这个线程。

2. 就绪状态

   当线程对象调用start()方法后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里的线程调度器的调度。

3. 执行状态

   如果就绪队列中的线程获得了处理机,就可以执行run()方法此时线程便处于运行状态。

4. 阻塞状态

   当一个线程执行了sleep(),suspend()等方法后,失去所占用资源之后,该线程就从运行态转化为阻塞态。在睡眠时间已到或获得设备资源后就可以重新进入就绪态。
阻塞态可以分为三种:

  • 等待阻塞:运行态中的线程执行了wait()方法,使线程进入等待阻塞态

  • 同步阻塞:线程在获取synchronized(同步)同步锁失败(因为同步锁被其他线程占用)。

  • 其他阻塞:在调用线程的sleep()或join()发出的I/O请求时,线程会进入到阻塞态,当sleep()态超时,join()等待线程终止或超时时,或者I/O处理完毕,线程重新转入就绪态。

5. 终止状态

一个运行态的线程完成任务或其他终止条件发生时,该线程就切换到终止态;

线程控制常用方法

方法说明
setPriority(int newPriority)更改线程的优先级
static void sleep(long millisecond)在指定毫秒数内让当前正在执行的线程休眠
void join()等待该线程终止
static void yield暂停正在执行的线程对象,并执行其他线程
void interrupt()中段线程
boolean isAlive()检测线程是否处于活动状态

线程的生命周期图示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sxk0v3Ix-1623500327402)(https://i.loli.net/2020/11/16/R2PTzGVN5OAKUx8.png)]

线程控制

停止线程

代码演示:

// 1.建议线程正常停止 --> 利用次数, 不建议使用死循环
// 2.建议使用标准位来控制线程,让其自己停下来
// 3.不建议使用stop()和destroy()

public class Stop implements Runnable {

    // 1.设置一个标志位
    private boolean flag = true;

    @Override
    public void run() {
        int i = 0;
        while (this.flag) {
            System.out.println("Thread Running " + i++);
        }
    }

    // 2.设置一个公开的方法停止线程, 转换标志位
    public void stop() {
        this.flag = false;
    }


    public static void main(String[] args) {
        Stop stop = new Stop();
        new Thread(stop).start();
        for (int i = 0; i < 1000; i++) {
            System.out.println("MainThread is running " + i);
            if (i == 666) {
                // 调用stop()方法切换标志位,让线程停止
                stop.stop();
                System.out.println("StopThread Stop, i = " + i);
            }
        }
    }
}

线程休眠

代码演示:

import java.text.SimpleDateFormat;
import java.util.Date;

// sleep(millisecond)指定当前线程阻塞的毫秒数
// sleep存在异常(interruptException)
// sleep完成后线程进入就绪状态
// sleep可以模拟网络延迟,倒计时等
// 每一个对象都有一个锁,sleep不会释放锁


// 利用线程控制来实现定时器
public class Timer {
    public static void main(String[] args) {

        Date starTime = new Date(System.currentTimeMillis());

        while (true) {
            try {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("HH:mm:ss").format(starTime));
                starTime = new Date(System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

线程礼让

代码演示:

public class TestYield {

    // 礼让线程,让当前正在执行的线程暂停,但不阻塞
    // 将线程从运行状态转为就绪状态

    public static void main(String[] args) {
        MyYield myYield = new MyYield();

        new Thread(myYield, "Thread-A").start();
        new Thread(myYield, "Thread-B").start();
    }
}

class MyYield implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " running");
        Thread.yield();         // 线程礼让
        System.out.println(Thread.currentThread().getName() + " be stopped");
    }
}


/*
运行结果;
        Thread-A running
        Thread-A be stopped
        Thread-B running
        Thread-B be stopped

 */

线程抢占

代码演示:

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

    public static void main(String[] args) throws InterruptedException {

        TestJoin testJoin = new TestJoin();
        Thread thread = new Thread(testJoin, "testJoin");
        thread.start();

        for (int i = 0; i < 1000; i++) {
            if (i == 200) {
                thread.join();
            }
            System.out.println("MainThread Running " + i);
        }
    }
}

观测线程的状态

代码演示:

// 监视线程的状态

public class ThreadMonitor {

    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("Thread is running");
        });

        // 监视

        Thread.State state = thread.getState();
        System.out.println(state);

        thread.start();
        state = thread.getState();
        System.out.println(state);

        while (state != Thread.State.TERMINATED) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            state = thread.getState();
            System.out.println(state);
        }
    }
}

线程优先级

代码演示:

// 测试线程的优先级
// 范围: 1 - 10
// 默认为 5

public class TestPriority {

    public static void main(String[] args) {
        MyPriority myPriority = new MyPriority();
        System.out.println(Thread.currentThread().getName() + " 的优先级为 " + Thread.currentThread().getPriority());

        Thread thread_A = new Thread(myPriority, "thread_A");


        Thread thread_B = new Thread(myPriority, "thread_B");
        thread_B.setPriority(7);


        Thread thread_C = new Thread(myPriority, "thread_C");
        thread_C.setPriority(10);


        Thread thread_D = new Thread(myPriority, "thread_D");
        thread_D.setPriority(4);


        Thread thread_E = new Thread(myPriority, "thread_E");
        thread_E.setPriority(1);


        thread_A.start();
        thread_B.start();
        thread_C.start();
        thread_D.start();
        thread_E.start();
    }
}

class MyPriority implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " 的优先级为 " + Thread.currentThread().getPriority());
    }
}

守护线程

代码演示:

// 线程分为用户线程和守护线程
// 虚拟机必须确保用户线程执行完毕
// 虚拟机不必等待守护线程(内存监控, 垃圾回收, 操作日志记录等等)完毕

// 测试守护线程

public class TestDaemon {

    public static void main(String[] args) {
        God god_ = new God();
        People people_ = new People();

        Thread god = new Thread(god_, "God");
        // 把God设置为守护线程
        god.setDaemon(true);

        Thread people = new Thread(people_, "people");

        god.start();
        people.start();
    }
}


class People implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 3000; i++) {
            System.out.println(Thread.currentThread().getName() + " 活着 " + i);
        }
        System.out.println(Thread.currentThread().getName() + " 死亡");
    }
}


class God implements Runnable {

    @Override
    public void run() {
        while (true) {
            System.out.println(Thread.currentThread().getName() + " 守护");
        }
    }
}

线程同步

  • 多个线程操作临界资源

并发

  • 理解并发

使用Lock,演示代码

import java.util.concurrent.locks.ReentrantLock;

public class UnsafeThread01 {

    public static void main(String[] args) {

        Sale sale = new Sale();

        Thread threadA = new Thread(sale, "APP");
        Thread threadB = new Thread(sale, "官网");
        Thread threadC = new Thread(sale, "票贩子");

        threadA.start();
        threadB.start();
        threadC.start();

    }
}

class Sale implements Runnable {

    // 票数
    int ticketNums = 10;
    boolean flag = true;
    public final ReentrantLock lock = new ReentrantLock();

    public void run() {
        buy();
    }

    // 售票
    public void buy() {

        while (flag) {
            try {
                lock.lock();
                if (ticketNums <= 0) {
                    flag = false;
                    break;
                }
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + " 卖出了第 " + ticketNums-- + " 张票");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
}

  • Lock是显示锁(手动开启和关闭锁,别忘记关闭锁),synchronized是隐式锁,出了作用域自动释放
  • Lock只有代码块锁,synchronized有代码块锁和方法锁
  • 使用Lock锁,JVM将花费较少的时间来调整线程,性能更好.并且具有更好的扩展性(能提供更多的子类)
  • 使用顺序
    • Lock > 同步代码块 > 同步方法

线程通信问题

生产者消费者模型

管程法:

package zl.Winter.Demo16_thread;

// 测试生产者消费者模型
// 管程法

public class TestPC {

    public static void main(String[] args) {
        SynContainer container = new SynContainer();

        Producer producer = new Producer(container);
        Costumer costumer = new Costumer(container);

        Thread thread_A = new Thread(producer,"生产者");
        Thread thread_B = new Thread(costumer,"消费者");

        thread_A.start();
        thread_B.start();

    }
}


// 生产者
class Producer implements Runnable {

    SynContainer container;

    public Producer(SynContainer container) {
        this.container = container;
    }

    // 生产
    @Override
    public void run() {
        for (int i = 1; i < 100; i++) {
            container.push(new Chicken(i));
            System.out.println("生产者生产了第" + i + "只鸡");
        }
    }
}


// 消费者
class Costumer implements Runnable {

    SynContainer container;

    public Costumer(SynContainer container) {
        this.container = container;
    }

    // 消费
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("消费者消费了-->>第" + container.pop().id + "只鸡");
        }
    }
}

// 产品
class Chicken {

    int id;
    public Chicken(int id) {
        this.id = id;
    }
}

// 缓冲区
class SynContainer {

    // 容器
    Chicken[] chickens = new Chicken[10];
    // 容器计数器
    int count = 0;

    // 生产者放入产品
    public synchronized void push(Chicken chicken) {

        // 容器满, 等待消费者消费
        if (count == chickens.length) {
            // 通知消费者消费, 生产者等待
            try{
                this.wait();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        // 容器没满, 放入产品
        chickens[count] = chicken;
        count++;

        // 通知消费者消费
        this.notifyAll();
    }


    // 消费者消费
    public synchronized Chicken pop() {

        // 判断是否能消费
        if (count == 0) {
            // 等待生产者生产, 消费者等待
            try{
                this.wait();
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }

        // 可以消费,生产者消费
        count--;
        Chicken chicken = chickens[count];

        // 消费完毕, 通知生产者生产
        this.notifyAll();
        return chicken;
    }
}

信号灯法:

// 测试生产者消费者模型
// 信号灯法

public class TestPC2 {

    public static void main(String[] args) {

        Cinema cinema = new Cinema();

        new Player(cinema).start();
        new Audience(cinema).start();
    }
}

// 生产者 --> 演员
class Player extends Thread {

    Cinema cinema;

    public Player(Cinema cinema1){
        this.cinema = cinema1;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if(i%2 == 0){
                this.cinema.play("<<大话西游>>");
            }else{
                this.cinema.play("广告: 你的益达");
            }
        }
    }
}

// 消费者 --> 观众
class Audience extends Thread {

    Cinema cinema;

    public Audience(Cinema cinema1){
        this.cinema = cinema1;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            this.cinema.watch();
        }
    }
}


// 产品 --> 节目
class Cinema{

    // 节目
    String program;
    // 演员是否在表演
    boolean flag = true;

    // 演员表演. 观众等待
    public synchronized void play(String program){
        if(!flag){
            try{
                this.wait();
            }catch (InterruptedException e){
                e.printStackTrace();
            }

            System.out.println("表演了" +  program);

            // 通知观众观看

            this.program = program;
            this.flag = !this.flag;
            this.notifyAll();
        }
    }

    // 观众观看, 演员等待
    public synchronized void watch(){
        if(flag){
            try{
                this.wait();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }

        System.out.println("观众观看了" + program);

        // 通知演员表演

        this.flag = !this.flag;
        this.notifyAll();
    }
}

线程池

高级主题

这篇关于java多线程编程的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!