多线程

1、创建多线程

1.1、继承Thread类

package demo;

/**
 * @description: demo01
 * @author: liuyang
 * @create: 2021-08-24 21:40
 */
public class Demo01 extends Thread {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        Demo01 myThread = new Demo01();
        myThread.setName("my-thread-test");
        myThread.start();
    }
}

1.2、实现Runnable接口

package demo;

/**
 * @description: demo02
 * @author: liuyang
 * @create: 2021-08-24 21:53
 */
public class Demo02 implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        // 方式1
        Thread myThread1 = new Thread(new Demo02());
        myThread1.setName("myThread1");
        myThread1.start();
        // 方式2-匿名内部类
        Thread myThread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });
        myThread2.setName("myThread2");
        myThread2.start();
        // 方式3--函数式编程
        Thread myThread3 = new Thread(() -> {
            System.out.println(Thread.currentThread().getName());
        });
        myThread3.setName("myThread3");
        myThread3.start();
    }
}

1.3、实现Callable接口(jdk5新增)

package demo;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @description: demo13
 * @author: liuyang
 * @create: 2021-08-27 9:24
 */
public class Demo13 implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        System.out.println("开始执行。。。");
        int sum = 0;
        for (int i = 1; i < 100; i++) {
            sum += i;
        }
        return sum;
    }

    public static void main(String[] args) {
        Demo13 demo13 = new Demo13();
        FutureTask<Integer> task = new FutureTask<>(demo13);
        Thread thread = new Thread(task);
        thread.start();
        try {
            // 获取线程执行结果
            Integer result = task.get();
            System.out.println("结果为:" + result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

1.4、使用线程池(jdk5新增)

package demo;

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

/**
 * @description: demo14
 * @author: liuyang
 * @create: 2021-08-27 10:07
 */
public class Demo14 {
    public static void main(String[] args) {
        // 创建固定线程数的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        // execute方法仅执行线程,无法获取返回值
        executorService.execute(new ThreadTest1());
        executorService.execute(new ThreadTest1());
        executorService.execute(new ThreadTest1());
        // submit可获取线程执行后的返回值
        Future<String> future1 = executorService.submit(new ThreadTest2());
        Future<String> future2 = executorService.submit(new ThreadTest2());
        try {
            // 获取线程执行结果
            String result1 = future1.get();
            String result2 = future2.get();
            System.out.println(result1);
            System.out.println(result2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        // 关闭线程池
        executorService.shutdown();
    }
}

class ThreadTest1 implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "---ThreadTest1");
    }
}

class ThreadTest2 implements Callable<String> {

    @Override
    public String call() throws Exception {
        System.out.println(Thread.currentThread().getName() + "---ThreadTest2");
        return "测试结果---" + Thread.currentThread().getName();
    }
}

 

2、线程优先级

2.1、设置线程优先级

package demo;

/**
 * @description: demo03
 * @author: liuyang
 * @create: 2021-08-25 10:45
 */
public class Demo03 extends Thread {
    @Override
    public void run() {
        test();
    }

    private void test() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "---" + i);
        }
    }

    public static void main(String[] args) {
        /**
         * 线程优先级范围1-10,默认为5。
         * 高优先级会抢占低优先级的线程的执行权,
         * 并非绝对,只是高优先级线程优先执行的概率更高。
         */
        Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
        Demo03 myThread = new Demo03();
        myThread.setName("myThread");
        myThread.setPriority(Thread.MAX_PRIORITY);
        myThread.start();
        myThread.test();
    }
}

3、线程分类

守护线程和用户线程,若只剩下守护线程则JVM将会退出

4、线程安全问题

4.1、同步代码块

4.1.1、实现Runnable接口方式的多线程

package demo;

/**
 * @description: demo05
 * @author: liuyang
 * @create: 2021-08-25 21:43
 */
public class Demo05 implements Runnable {
    private int ticket = 100;
    @Override
    public void run() {
        while (true) {
            /**
             * 同步代码块解决实现Runnable多线程安全问题
             * 锁的要求:
             * 任何一个类的对象都能作为锁,且这些线程必需共用一个锁。
             */
            synchronized (this) {
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "---" + ticket);
                    ticket --;
                } else {
                    break;
                }
            }
        }
    }

    public static void main(String[] args) {
        Demo05 demo = new Demo05();
        Thread thread1 = new Thread(demo);
        thread1.setName("窗口1");
        thread1.start();
        Thread thread2 = new Thread(demo);
        thread2.setName("窗口2");
        thread2.start();
        Thread thread3 = new Thread(demo);
        thread3.setName("窗口3");
        thread3.start();
    }
}

 

4.1.2、继承Thread类方式的多线程

package demo;

/**
 * @description: demo06
 * @author: liuyang
 * @create: 2021-08-25 21:43
 */
public class Demo06 extends Thread {
    private static int ticket = 100;

    @Override
    public void run() {
        while (true) {
            /**
             * 同步代码块解决继承Thread类多线程线程安全问题
             * 锁的要求:
             * 任何一个类的对象都能作为锁,且这些线程必需共用一个锁。
             */
            synchronized (Demo06.class) {
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "---" + ticket);
                    ticket --;
                } else {
                    break;
                }
            }
        }
    }

    public static void main(String[] args) {
        Demo06 thread1 = new Demo06();
        thread1.setName("窗口1");
        thread1.start();
        Demo06 thread2 = new Demo06();
        thread2.setName("窗口2");
        thread2.start();
        Demo06 thread3 = new Demo06();
        thread3.setName("窗口3");
        thread3.start();
    }
}

4.2、同步方法

4.2.1、实现Runnable接口方式的多线程

package demo;

/**
 * @description: demo07
 * @author: liuyang
 * @create: 2021-08-25 21:43
 */
public class Demo07 implements Runnable {
    private int ticket = 100;
    @Override
    public void run() {
        while (true) {
            ticketing();
        }
    }

    // 同步方法的锁默认为this
    private synchronized void ticketing() {
        if (ticket > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "---" + ticket);
            ticket --;
        }
        else {
            System.exit(0);
        }
    }


    public static void main(String[] args) {
        Demo07 demo = new Demo07();
        Thread thread1 = new Thread(demo);
        thread1.setName("窗口1");
        thread1.start();
        Thread thread2 = new Thread(demo);
        thread2.setName("窗口2");
        thread2.start();
        Thread thread3 = new Thread(demo);
        thread3.setName("窗口3");
        thread3.start();
    }
}

4.2.2、继承Thread类方式的多线程

package demo;

/**
 * @description: demo06
 * @author: liuyang
 * @create: 2021-08-25 21:43
 */
public class Demo08 extends Thread {
    private static int ticket = 100;

    @Override
    public void run() {
        while (true) {
            ticketing();
        }
    }

    /**
     * 同步方法解决继承Thread多线程安全问题
     * 该方法需声明为static,保证锁的唯一性,此时锁为Demo08.class
     */
    private synchronized static void ticketing() {
        if (ticket > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "---" + ticket);
            ticket --;
        } else {
            System.exit(0);
        }
    }

    public static void main(String[] args) {
        Demo08 thread1 = new Demo08();
        thread1.setName("窗口1");
        thread1.start();
        Demo08 thread2 = new Demo08();
        thread2.setName("窗口2");
        thread2.start();
        Demo08 thread3 = new Demo08();
        thread3.setName("窗口3");
        thread3.start();
    }
}

4.3、Lock

4.3.1、实现Runnable接口的多线程

package demo;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @description: demo10
 * @author: liuyang
 * @create: 2021-08-26 10:54
 */
public class Demo10 implements Runnable {
    private int ticket = 100;
    // 定义锁
    private ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true) {
            // 将处理多线程共享资源的代码用try包起来
            try {
                // 先锁住共享资源的处理逻辑
                lock.lock();
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + "---" + ticket);
                    ticket --;
                } else {
                    break;
                }
            } finally {
                // 共享资源处理完成后释放锁
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        Demo10 demo10 = new Demo10();
        for (int i = 0; i < 10; i++) {
            Thread t = new Thread(demo10);
            t.setName("窗口" + (i + 1));
            t.start();
        }
    }
}

5、线程之间通信

5.1、例题:线程1和线程2交替输出数字

package demo;

/**
 * @description: demo11
 * @author: liuyang
 * @create: 2021-08-26 18:06
 */
public class Demo11 implements Runnable {
    private int num = 1;
    @Override
    public void run() {
        while (true) {
            synchronized (this) {
                /**
                 * notify:
                 * 唤醒一个被阻塞的线程到就绪状态,
                 * 若有多个被阻塞的线程则优先唤醒优先级高的那个线程。
                 * notifyAll:
                 * 唤醒所有被阻塞的线程。
                 * sleep:
                 * 会令当前线程阻塞,但并不会释放锁。
                 * wait、notify、notifyAll这三个方法的调用者必须相同且必须为锁对象且这三个方法必须在同步代码块或者同步方法中使用。
                 */
                notify();
                if (num <= 100) {
                    System.out.println(Thread.currentThread().getName() + "---" + num);
                    num ++;
                    try {
                        // wait会令当前线程阻塞且会释放锁
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    break;
                }
            }
        }
    }

    public static void main(String[] args) {
        Demo11 demo = new Demo11();
        Thread t1 = new Thread(demo);
        t1.setName("线程1");
        Thread t2 = new Thread(demo);
        t2.setName("线程2");
        t1.start();
        t2.start();
    }
}

5.2、例题:典型的生产者和消费者问题

package demo;

/**
 * @description: demo12
 * @author: liuyang
 * @create: 2021-08-26 21:22
 */
public class Demo12 {
    public static void main(String[] args) {
        Clerk clerk = new Clerk();
        // 创建生产者线程
        Producer producerThread = new Producer(clerk);
        producerThread.setName("生产者线程1");
        // 创建消费者线程
        Consumer consumerThread1 = new Consumer(clerk);
        consumerThread1.setName("消费者线程1");
        Consumer consumerThread2 = new Consumer(clerk);
        consumerThread2.setName("消费者线程2");
        // 启动生产者和消费者线程
        producerThread.start();
        consumerThread1.start();
        consumerThread2.start();
    }
}

/**
 * 店员类
 */
class Clerk {
    // 商品数量
    private int cnt = 0;

    /**
     * 生产
     */
    public synchronized void produce() {
        if (cnt < 20) {
            cnt ++;
            System.out.println(Thread.currentThread().getName() + "开始生产第" + cnt + "个商品");
            // 每次生产完后就可以消费了
            notify();
        } else {
            // 数量大于或者等于20时阻塞生产者线程并释放锁
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 消费
     */
    public synchronized void consume() {
        if (cnt > 0) {
            System.out.println(Thread.currentThread().getName() + "开始消费第" + cnt + "个商品");
            cnt --;
            // 每次消费完成后又可以恢复生产了
            notify();
        } else {
            // 数量等于0时阻塞消费线程并释放锁
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

/**
 * 生产者线程类
 */
class Producer extends Thread {
    private Clerk clerk;

    public Producer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 调用生产
            clerk.produce();
        }
    }
}

/**
 * 消费则线程类
 */
class Consumer extends Thread {
    private Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 调用消费
            clerk.consume();
        }
    }
}

 

posted @ 2021-08-24 22:18  牛牛的自留地  阅读(22)  评论(0编辑  收藏  举报