多线程11-28

本文介绍了Java中的线程控制方法(如停止、休眠、礼让和强制执行)、线程优先级的概念及使用,守护线程的作用,同步机制(synchronized和Lock),死锁的原理与示例,以及线程池的概念和自定义线程池的实现。
摘要由CSDN通过智能技术生成

线程停止,线程休眠,线程礼让,线程强制执行

public class ThreadDemo {

    public static void main(String[] args) {
        // 创建并启动线程1
        Thread thread1 = new Thread(new MyRunnable(), "Thread 1");
        thread1.start();

        // 创建并启动线程2
        Thread thread2 = new Thread(new MyRunnable(), "Thread 2");
        thread2.start();

        // 线程停止
        try {
            Thread.sleep(1000); // 主线程休眠1秒
            thread1.interrupt(); // 停止线程1
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 线程休眠
        try {
            Thread.sleep(1000); // 主线程休眠1秒
            Thread.yield(); // 主线程礼让
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 线程强制执行
        try {
            Thread.sleep(1000); // 主线程休眠1秒
            thread2.join(); // 强制主线程等待线程2执行完毕
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Main thread is ending...");
    }

    static class MyRunnable implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + " is running... " + i);
                try {
                    Thread.sleep(500); // 线程休眠500毫秒
                } catch (InterruptedException e) {
                    System.out.println(Thread.currentThread().getName() + " is interrupted...");
                    return;
                }
            }
            System.out.println(Thread.currentThread().getName() + " is ending...");
        }
    }
}

线程的优先级

在Java中,线程的优先级用整数表示,范围从1到10。线程的优先级越高,CPU调度器就越倾向于让该线程先执行。可以使用setPriority方法设置线程的优先级,如下所示:

Thread thread = new Thread(new MyRunnable());
thread.setPriority(Thread.MAX_PRIORITY); // 设置线程的优先级为最高

在博客中可以介绍线程优先级的作用、使用方法,以及在实际开发中如何合理地使用线程优先级。

守护线程

守护线程是一种特殊的线程,它的作用是为其他线程提供服务。当所有的非守护线程结束时,守护线程会自动终止。可以使用setDaemon方法将线程设置为守护线程,如下所示:

Thread daemonThread = new Thread(new DaemonRunnable());
daemonThread.setDaemon(true); // 设置为守护线程

在博客中可以介绍守护线程的作用、使用方法,以及它与普通线程的区别和注意事项。

线程同步机制

在多线程环境中,如果多个线程同时访问共享资源,可能会导致数据不一致或其他问题。线程同步机制可以解决这个问题,常用的同步机制包括synchronized关键字和Lock接口。以下是一个使用synchronized关键字实现线程同步的示例:

static class SynchronizedRunnable implements Runnable {
    private int count = 0;

    @Override
    public void run() {
        synchronized (this) {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + " is running... " + count++);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

死锁

什么是死锁?

死锁是指两个或多个线程在互相等待对方释放资源而无法继续执行的状态。这种情况下,线程无法终止,程序也无法继续执行下去。

死锁示例

下面是一个简单的死锁示例:

public class DeadlockExample {
    private static final Object lock1 = new Object();
    private static final Object lock2 = new Object();

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            synchronized (lock1) {
                System.out.println("Thread 1: Holding lock 1...");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {}
                System.out.println("Thread 1: Waiting for lock 2...");
                synchronized (lock2) {
                    System.out.println("Thread 1: Holding lock 1 and lock 2...");
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (lock2) {
                System.out.println("Thread 2: Holding lock 2...");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {}
                System.out.println("Thread 2: Waiting for lock 1...");
                synchronized (lock1) {
                    System.out.println("Thread 2: Holding lock 1 and lock 2...");
                }
            }
        });

        thread1.start();
        thread2.start();
    }
}

如何避免死锁?

避免死锁的方法包括:避免使用多个锁、按照相同的顺序获取锁、设置超时时间等。在博客中可以详细介绍这些方法,并提供示例说明。

Lock锁

什么是Lock锁?

Lock锁是Java.util.concurrent包中提供的一种线程同步机制,它提供了比传统的synchronized关键字更灵活的方式来控制线程的访问。Lock锁可以使用tryLock()方法来避免死锁,也可以实现公平锁、读写锁等。

Lock锁示例

下面是一个使用Lock锁的示例:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockExample {
    private static Lock lock = new ReentrantLock();

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            lock.lock(); // 获取锁
            try {
                System.out.println("Thread 1: Holding the lock...");
                Thread.sleep(100); // 模拟线程持有锁的操作
            } catch (InterruptedException e) {
            } finally {
                lock.unlock(); // 释放锁
                System.out.println("Thread 1: Released the lock...");
            }
        });

        Thread thread2 = new Thread(() -> {
            lock.lock(); // 获取锁
            try {
                System.out.println("Thread 2: Holding the lock...");
                Thread.sleep(100); // 模拟线程持有锁的操作
            } catch (InterruptedException e) {
            } finally {
                lock.unlock(); // 释放锁
                System.out.println("Thread 2: Released the lock...");
            }
        });

        thread1.start();
        thread2.start();
    }
}

Lock锁的特性

在博客中可以介绍Lock锁的特性,比如可重入性、公平性、读写锁等,并提供示例来说明这些特性。


线程池


概述

提到池,大家应该能想到的就是水池。水池就是一个容器,在该容器中存储了很多的水。那么什么是线程池呢?线程池也是可以看做成一个池子,在该池子中存储很多个线程。

线程池存在的意义:

系统创建一个线程的成本是比较高的,因为它涉及到与操作系统交互,当程序中需要创建大量生存期很短暂的线程时,频繁的创建和销毁线程对系统的资源消耗有可能大于业务处理是对系

统资源的消耗,这样就有点”舍本逐末”了。针对这一种情况,为了提高性能,我们就可以采用线程池。线程池在启动的时,会创建大量空闲线程,当我们向线程池提交任务的时,线程池就

会启动一个线程来执行该任务。等待任务执行完毕以后,线程并不会死亡,而是再次返回到线程池中称为空闲状态。等待下一次任务的执行。

自定义线程池


线程池的设计思路:

  • 线程池的思路和生产者消费者模型是很接近的
  • 准备一个任务容器
  • 一次性启动多个(2个)消费者线程
  • 刚开始任务容器是空的,所以线程都在wait
  • 直到一个外部线程向这个任务容器中扔了一个”任务”,就会有一个消费者线程被唤醒
  • 这个消费者线程取出”任务”,并且执行这个任务,执行完毕后,继续等待下一次任务的到来
  • 在整个过程中,都不需要创建新的线程,而是循环使用这些已经存在的线程。

代码实现

实现思路:

  • 创建一个线程池类(ThreadPool)
  • 在该类中定义两个成员变量poolSize(线程池初始化线程的个数) , BlockingQueue<Runnable>(任务容器)
  • 通过构造方法来创建两个线程对象(消费者线程),并且启动
  • 使用内部类的方式去定义一个线程类(TaskThread),可以提供一个构造方法用来初始化线程名称
  • 两个消费者线程需要不断的从任务容器中获取任务,如果没有任务,则线程处于阻塞状态。
  • 提供一个方法(submit)向任务容器中添加任务
  • 定义测试类进行测试
public class ThreadPool {
    // 初始化线程个数
    private static final int DEFAULT_POOL_SIZE = 2 ;
    // 在该类中定义两个成员变量poolSize(线程池初始化线程的个数) , BlockingQueue<Runnable>(任务容器)
    private int poolSize = DEFAULT_POOL_SIZE ;
    private BlockingQueue<Runnable> blockingQueue = new LinkedBlockingQueue<Runnable>() ;
    // 无参构造方法
    public ThreadPool(){
        this.initThread();
    }
    // 有参构造方法,通过构造方法来创建两个线程对象(消费者线程),并且启动
    public ThreadPool(int poolSize) {
        if(poolSize > 0) {
            this.poolSize = poolSize ;
        }
        this.initThread();
    }
    // 初始化线程方法
    public void initThread(){
        for(int x = 0 ; x < poolSize ; x++) {
            new TaskThread("线程--->" + x).start();
        }
    }
    // 提供一个方法(submit)向任务容器中添加任务
    public void submit(Runnable runnable) {
        try {
            blockingQueue.put(runnable);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    // 使用内部类的方式去定义一个线程类
    public class TaskThread extends Thread {
        // 提供一个构造方法,用来初始化线程名称
        public TaskThread(String name) {
            super(name);
        }
        @Override
        public void run() {
            while(true) {
                try {
                    // 两个消费者线程需要不断的从任务容器中获取任务,如果没有任务,则线程处于阻塞状态。
                    Runnable task = blockingQueue.take();
                    task.run();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
public class ThreadPoolDemo01 {
    public static void main(String[] args) {
        // 创建线程池对象,无参构造方法创建
        // ThreadPool threadPool = new ThreadPool();
        ThreadPool threadPool = new ThreadPool(5);
        // 提交任务
        for(int x = 0 ; x < 10 ; x++) {
            threadPool.submit( () -> {
                System.out.println(Thread.currentThread().getName() + "---->>>处理了任务");
            });
        }
    }
}

  • 16
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值