小言_互联网的博客

Java常用业务代码-线程篇

432人阅读  评论(0)

本篇文章将Java线程中常见的功能进行整理,涉及点:join、yield、isAlive方法、synchronized的使用、生产者-消费者模式(wait/notify实现和阻塞队列实现)、Lock+Condition模拟阻塞队列、线程同步工具、模拟死锁程序、jstack寻找死锁程序。

join

join类似于同步,当A线程中调用了B线程的join()方法时,表示只有当B线程执行完毕时,A线程才能继续执行(如下代码), 但是B线程必须已经调用start()方法,否则join就会失效

   public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(()->{
            System.out.println("我是线程start");
            try {
             	System.out.println("等待3秒");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("我是线程end");
        });
        thread.start();
        thread.join();
        System.out.println("我是线程2 正常情况下肯定是我先执行完,但是加入join后,main主线程会等待子线程执行完毕后才执行");
    }

yield

yield,可以理解为让步,对于运行的线程(占有CPU资源),可以通过yield方法 让出其占有的CPU,让其它具有相同优先级的等待线程获取执行权;但是,并不能保证 让出CPU后其他等待线程一定能拿到执行权。

这里是两个线程交叉打印。

 public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 10; i += 2) {
                System.out.println("线程1:" + i);
                Thread.yield();
            }
        });
        Thread thread2 = new Thread(() -> {
            for (int i = 1; i < 10; i += 2) {
                System.out.println("线程2:" + i);
                Thread.yield();
            }
        });
        thread1.start();
        thread2.start();
    }

isAlive

isAlive()方法来检查线程是否已停止

   public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (true){
            }
        });
        thread.start();
        System.out.println("线程是否存活"+thread.isAlive());
    }

synchronized

synchronized是Java中的关键字,是一种同步锁, 我们使用多线程通常是为了达到异步的目的,但是异步也带来一些安全问题, 对于一些多线程访问的资源,可能我们更多的是要求资源在某一时刻只被一个线程占有,这个时候就需要我们 做一些操作保证资源不被多个线程同时拥有。

public static void syn() {
        new Thread(() -> {
            System.out.println("syn1");
            exe();
            System.out.println("--");
        }).start();
        new Thread(() -> {
            System.out.println("syn2");
            exe();
            System.out.println("--");
        }).start();

    }
    static int i = 0;
    private static synchronized void exe() {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + ":" + ++i);
    }
    
  public static void main(String[] args) {
        syn();
    }

生产者消费者模式

生产者消费者模式是一个多线程同步问题的经典案例, 其目的是解决当多个线程共同去操作同一份数据时,使用线程的同步保证信息的同步性和安全性。这里使用 wait-notify 和 阻塞队列(ArrayBlockingQueue)实现。

需要注意的是如果使用LinkedBlockingQueue实现,需要考虑LinkedBlockingQueue默认Integer.MAX_VALUE大小容量, 如果生产者的速度一旦大于消费者的速度,也许还没有等到队列满阻塞产生,系统内存就有可能已被消耗殆尽了。

   //wait-notify实现
    private static void produceCustom() {

        Queue<Long> queue = new LinkedList<>();

        Thread produce = new Thread(() -> {
            while (true) {
                //不上锁会IllegalMonitorStateException
                synchronized (queue) {
                    while (queue.size() == 10) {
                        try {
                            queue.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("开始生产");
                    queue.add(System.currentTimeMillis());
                    queue.notifyAll();
                }
            }
        });

        Thread customer = new Thread(() -> {
            while (true) {
                synchronized (queue) {
                    while (queue.isEmpty()) {
                        try {
                            queue.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("移除元素:" + queue.remove());
                    queue.notifyAll();
                }
            }
        });
        produce.start();
        customer.start();
    }

    //阻塞队列实现生产者消费者
    private static void produceCustomBlockQueue() {
        BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);
        new Thread(() -> {
            while (true) {
                boolean res = queue.offer(i);
                if (res) {
                    System.out.println("存放元素");
                    ++i;
                }
            }
        }).start();
        new Thread(() -> {
            while (true) {
                try {
                    System.out.println("take:" + queue.take());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

	//测试两种方式
    public static void main(String[] args) {
        //wait-notify实现
        produceCustom();
        //阻塞队列实现生产者消费者
        produceCustomBlockQueue();
    }

死锁

死锁的四个必要条件:(1) 互斥条件:一个资源每次只能被一个进程使用。(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

  public static void main(String[] args) {
        deadLock();
    }
    
    public static void deadLock() {
        Object o = new Object();
        Object o1 = new Object();

        new Thread(() -> {
            synchronized (o) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (o1) {
                    System.out.println("+");
                }
            }
        }).start();

        new Thread(() -> {
            synchronized (o1) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (o) {
                    System.out.println("-");
                }
            }
        }).start();
    }

转载:https://blog.csdn.net/qq_41871159/article/details/106564365
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场