【Java复习巩固 Day8】多线程

单线程程序只有一个顺序执行流,多线程的程序则可以包括多个顺序执行流,多个顺序流之间互不干扰

现在的操作系统大多数都支持同时运行多个任务,一个任务通常是一个程序,每个运行的程序就是一个进程。当一个程序运行时,内部可能包含了多个顺序执行流,每个顺序执行流就是一个线程

并行指在同一时刻,有多条指令在多个处理器上同时执行
并发指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果

一个程序运行后至少有一个进程,一个进程里可以包含多个线程,但至少包含一个线程

操作系统可以同时执行多个任务,每个任务就是进程,进程可以同时执行多个任务,每个任务就是线程

线程的创建和启动

方式一:继承Thread类重写run方法

package day8;

// 创建线程方式一:继承Thread类,重写run()方法,调用start()方法开启线程
public class ThreadTest1 extends Thread {
    public static void main(String[] args) {
        // 创建一个线程对象
        ThreadTest1 thread = new ThreadTest1();
        // 调用start方法
        thread.start();
        // 主线程
        for (int i = 0; i < 200; i++) {
            System.out.println("我在学习多线程... " + i);
        }
    }

    @Override
    public void run() {
        // run方法线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("我在看代码... " + i);
        }
    }
}

方式二:实现Runnable接口

package day8;

// 创建线程的方式2:实现Runnable接口,重写run方法
public class ThreadTest3 implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("我在看代码... " + i);
        }
    }

    public static void main(String[] args) {
        ThreadTest3 threadTest3 = new ThreadTest3();
        Thread thread = new Thread(threadTest3);
        thread.start();
        for (int i = 0; i < 200; i++) {
            System.out.println("我在学习多线程... " + i);
        }
    }
}

方式三:实现Callable接口

package day8;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


// 线程创建方式三:实现callable接口
public class ThreadTest5 implements Callable<Boolean> {
    @Override
    public Boolean call() throws Exception {
        for (int i = 0; i < 20; i++) {
            System.out.println("我在看代码... " + i);
        }
        return true;
    }

    public static void main(String[] args) {
        ThreadTest5 thread1 = new ThreadTest5();
        ThreadTest5 thread2 = new ThreadTest5();
        ThreadTest5 thread3 = new ThreadTest5();
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        executorService.submit(thread1);
        executorService.submit(thread2);
        executorService.submit(thread3);
        executorService.shutdown();


        for (int i = 0; i < 100; i++) {
            System.out.println("我在学习多线程... " + i);
        }
    }
}

线程的生命周期

在线程的生命周期中,它要经过新建、就绪、运行、阻塞和死亡5中状态
【Java复习巩固 Day8】多线程_第1张图片

package day8;

/**
 * 观察线程的状态
 */
public class ThreadStateTest {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("=====");
        });
        // 观察状态
        Thread.State state = thread.getState();
        System.out.println(state);
        thread.start();
        state = thread.getState();
        System.out.println(state);
        while (state != Thread.State.TERMINATED) {
            Thread.sleep(100);
            state = thread.getState(); // 更新状态
            System.out.println(state); // 打印状态
        }
    }
}

NEW
RUNNABLE
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
=====
TERMINATED

Process finished with exit code 0

线程控制

join

package day8;
// 测试join方法
public class ThreadJoinTest implements Runnable {
    public static void main(String[] args) throws InterruptedException {
        ThreadJoinTest threadJoinTest = new ThreadJoinTest();
        Thread thread = new Thread(threadJoinTest);
        thread.start();

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

    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("线程VIP来了... " + i);
        }
    }
}

sleep

package day8;

/**
 * 模拟网络延时
 */
public class ThreadSleepTest1 implements Runnable {
    private int ticketNums = 10;
    @Override
    public void run() {
        while (true) {
            if (ticketNums <= 0) {
                break;
            }
            // 模拟延时
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ": " + ticketNums--);
        }
    }

    public static void main(String[] args) {
        ThreadSleepTest1 threadSleepTest1 = new ThreadSleepTest1();
        new Thread(threadSleepTest1, "A").start();
        new Thread(threadSleepTest1, "B").start();
    }
}

yield

package day8;
// 测试线程礼让
// 礼让不一定成功
public class ThreadYieldTest {
    public static void main(String[] args) {
        MyThread thread = new MyThread();

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

class MyThread implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " 线程开始执行。。。");
        Thread.yield();
        System.out.println(Thread.currentThread().getName() + " 线程停止执行。。。");
    }
}

线程同步

同步代码块

synchronized(obj) {
 ...
}

任何时刻只能有一个线程可以获得对同步监视器的锁定,当同步代码块执行完成后,该线程会释放对该同步监视器的锁定

同步方法
与同步代码块对应,Java多线程安全支持还提供了同步方法,同步方法是使用synchronized关键字来修饰某个方法

public synchronized void play() {
 ...
}

Lock提供了比synchronized更加广泛的锁定操作,Lock允许实现灵活的结构,可以具有差别很大的属性,并且支持多个相关的Condition对象

package day8;

import java.util.concurrent.locks.ReentrantLock;

/**
 * 账户取钱
 */
public class LockTest {
    public static void main(String[] args) {
        MyAccount myAccount = new MyAccount();
        for (int i = 0; i < 5; i++) {
            new Thread(myAccount, "线程" + i).start();
        }
    }
}

class MyAccount implements Runnable {
    private final ReentrantLock lock = new ReentrantLock();
    private int money = 1000;

    private void draw() {
        lock.lock();
        try {
            if (money > 0) {
                System.out.println(Thread.currentThread().getName() + " --> 取钱成功!");
                money -= 500;
                System.out.println("余额为:" + money);
                // 模拟取钱的延时
                Thread.sleep(1000);
            } else {
                System.out.println(Thread.currentThread().getName() + " --> 取钱失败,余额不足!");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void run() {
        draw();
    }
}
线程0 --> 取钱成功!
余额为:500
线程2 --> 取钱成功!
余额为:0
线程1 --> 取钱失败,余额不足!
线程3 --> 取钱失败,余额不足!
线程4 --> 取钱失败,余额不足!

Process finished with exit code 0

线程通信

传统的线程通信

可以借助Object类提供的wait()、notify()和notifyAll()三个方法,但这三个方法必须由同步监视器对象来调用

package day8;

import java.util.LinkedList;

public class ThreadCommunicationTest {
    public static void main(String[] args) {
        LinkedList<String> list = new LinkedList<>();
        new P(list).start();
        new C(list).start();
    }
}

class P extends Thread {
    final LinkedList<String> linkedList;

    public P(LinkedList<String> list) {
        super("生产者");
        this.linkedList = list;
    }

    @Override
    public void run() {
        String[] strings = new String[]{"Java", "C++", "C", "Python"};
        for (int i = 0; i < 99; i++) {
            // 模拟生产延时
            try {
                sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (linkedList) {
                String item = strings[i % strings.length];
                linkedList.add(item);
                System.out.println(getName() + "生产了" + item);
                linkedList.notify(); // 通知消费者消费
            }
        }
    }
}

class C extends Thread {
    final LinkedList<String> linkedList;

    public C(LinkedList<String> list) {
        super("消费者");
        this.linkedList = list;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            synchronized (linkedList) {
                if (linkedList.size() == 0) {
                    try {
                        linkedList.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(getName() + "消费了" + linkedList.pollLast());
            }
        }
    }
}

使用阻塞队列控制线程通信

package day8;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class BlockingQueueTest {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(4);
        for (int i = 0; i < 5; i++) {
            new Producer(blockingQueue).start();
        }
        new Consumer(blockingQueue).start();
    }
}

class Producer extends Thread {
    private BlockingQueue<String> blockingQueue;

    public Producer(BlockingQueue<String> blockingQueue) {
        this.blockingQueue = blockingQueue;
    }

    @Override
    public void run() {
        String[] strings = new String[]{"Java", "C++", "C", "Python"};
        System.out.println(getName()+"开始生产了...");
        for (int i = 0; i < 5; i++) {
            try {
                Thread.sleep(500);
                blockingQueue.put(strings[i % strings.length]);
                System.out.println(getName() + "生产了" + strings[i % strings.length]);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Consumer extends Thread {
    private BlockingQueue<String> blockingQueue;

    public Consumer(BlockingQueue<String> blockingQueue) {
        this.blockingQueue = blockingQueue;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(100);
                System.out.println(getName() + "消费了" + blockingQueue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

线程池

系统启动一个新线程的成本比较高,因为它涉及与操作系统交互。在这种情况下,使用线程池可以很好地提高性能

使用线程池来执行线程任务的步骤
1、创建线程池
2、创建线程执行任务
3、将执行任务提交给线程池
4、关闭线程池

package day8;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolTest {
    public static void main(String[] args) throws Exception {
        // 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(8);
        // 创建执行任务
        Runnable target = () -> {
          for (int i = 0; i < 100; i++) {
              System.out.println(Thread.currentThread().getName() + "--> " + i);
          }
        };
        // 提交执行任务
        executorService.submit(target);
        executorService.submit(target);
        // 关闭线程池
        executorService.shutdown();
    }
}


你可能感兴趣的:(Java,java,多线程)