Java三个线程轮流搞事以及定时任务线程池

Java三个线程轮流搞事以及定时任务线程池,第1张

Java三个线程轮流搞事以及定时任务线程池

Java三个线程轮流搞事以及定时任务线程池
  • 三个线程轮流打印ABC
  • 三个线程轮流输出从1-100
  • Java核心技术卷I上的内容
  • 任务线程池的一个使用示例

三个线程轮流打印ABC
package tacos.thread;

import org.junit.Test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class ThreadDemo {
    public static String threadName = "A"; // 默认为A
    public static Lock lock = new ReentrantLock();
    public static Condition conA = lock.newCondition();
    public static Condition conB = lock.newCondition();
    public static Condition conC = lock.newCondition();

    @Test
    public void test() {
        ExecutorService es = Executors.newFixedThreadPool(3);
        // 线程开始执行的顺序和结果是无关的
        es.execute(new ThreadB());
        es.execute(new ThreadC());
        es.execute(new ThreadA());
        // es.execute(new ThreadB());
        // es.execute(new ThreadC());
        
		// 单独运行test()方法时,当前线程需要暂停一段时间才能保证每个任务都能顺利输出10次;
        // 如果把整个java项目启动运行起来,就不需要下面暂停当前线程这一步
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        es.shutdown();
    }

    class ThreadA implements Runnable {

        @Override
        public void run() {
            for(int k=1; k<=10; k++) {
                lock.lock();
                try {
                	// 这里必须用while, 不断地尝试才行
                    while (!threadName.equals("A")) {
                        try {
                        	// 在await即放弃锁前,就得先把其他可能阻塞的线程激活,避免出现所有线程都阻塞的状态
                            conB.signal();
                            conC.signal();
                            conA.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("A" + k);
                    threadName = "B";
                    conB.signal();
                } finally {
                	// 自己释放锁,就会进入同步队列;和调用await进入等待队列是不同的;前者释放锁后仍然可以加入锁竞争
                    lock.unlock();
                }
            }
        }
    }

    class ThreadB implements Runnable {

        @Override
        public void run() {
            for(int k=1; k<=10; k++) {
                lock.lock();
                try {
                    while (!threadName.equals("B")) {
                        try {
                            conC.signal();
                            conA.signal();
                            conB.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("B" + k);
                    threadName = "C";
                    conC.signal();
                } finally {
                    lock.unlock();
                }
            }
        }
    }

    class ThreadC implements Runnable {

        @Override
        public void run() {
            for(int k=1; k<=10; k++) {
                lock.lock();
                try {
                    while (!threadName.equals("C")) {
                        try {
                            conA.signal();
                            conB.signal();
                            conC.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("C" + k);
                    threadName = "A";
                    conA.signal();
                } finally {
                    lock.unlock();
                }
            }
        }
    }
}


三个线程轮流输出从1-100
package tacos.thread;

import org.junit.Test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class ThreadDemo2 {
    public volatile static AtomicInteger num = new AtomicInteger(0);
    public static Lock lock = new ReentrantLock();
    public static Condition conA = lock.newCondition();
    public static Condition conB = lock.newCondition();
    public static Condition conC = lock.newCondition();

    @Test
    public void test() {
        ExecutorService es = Executors.newFixedThreadPool(3);
        es.execute(new ThreadA());
        es.execute(new ThreadB());
        es.execute(new ThreadC());
        // 单独运行test()方法时,当前线程需要暂停一段时间才能保证顺利输出到100;
        // 如果把整个java项目启动运行起来,就不需要下面暂停当前线程这一步
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        es.shutdown();
    }

    class ThreadA implements Runnable {

        @Override
        public void run() {
            while(true) {
                lock.lock();
                try {
                    while (num.get() % 3 != 0) {
                        try {
                            conB.signal();
                            conC.signal();
                            conA.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    if(num.get() > 99) {
                        break;
                    }
                    System.out.println(Thread.currentThread().getName() + "  " + (num.getAndIncrement() + 1));
                    conB.signal();
                } finally {
                    lock.unlock();
                }
            }
        }
    }

    class ThreadB implements Runnable {

        @Override
        public void run() {
            while(true) {
                lock.lock();
                try {
                    while (num.get() % 3 != 1) {
                        try {
                            conC.signal();
                            conA.signal();
                            conB.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    if(num.get() > 99) {
                        break;
                    }
                    System.out.println(Thread.currentThread().getName() + "  " + (num.getAndIncrement() + 1));
                    conC.signal();
                } finally {
                    lock.unlock();
                }
            }
        }
    }

    class ThreadC implements Runnable {

        @Override
        public void run() {
            while(true) {
                lock.lock();
                try {
                    while (num.get() % 3 != 2) {
                        try {
                            conA.signal();
                            conB.signal();
                            conC.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    if(num.get() > 99) {
                        break;
                    }
                    System.out.println(Thread.currentThread().getName() + "  " + (num.getAndIncrement() + 1));
                    System.out.println();
                    conA.signal();
                } finally {
                    lock.unlock();
                }
            }
        }
    }
}


Java核心技术卷I上的内容

conA.await():
1)当前线程会暂停,并放弃锁,此时其他线程就有可能获取锁并执行。等待获取锁的线程(在同步队列中)和已经调用了await方法的线程(在conA对应的等待队列中)本质上就不同;因为一个线程一旦调用await方法,就会释放锁并进入等待队列,当锁可用时这个线程也不会变为可运行状态去竞争锁,而是仍保持非活动状态,知道另一个线程在conA这个条件上调用singal或者singalAll方法。
2)如果另一个线程在conA这个条件上调用singal或者singalAll方法,conA等待队列中的线程就会从等待队列中移出,进入同步队列,重新变为可运行的线程。同时,它们会重新进入该对象(也就是重新竞争锁),一旦锁可用(竞争到了锁),他们中的某个线程将从await调用返回,得到这个锁,并从之前暂停的地方继续执行。

conA.singalAll():
1)最终需要有某个其他线程调用singalAll方法,这一点至关重要。当一个线程调用await时,它没有办法重新自行激活。它寄希望于其他线程。如果没有其他线程来重新激活等待队列中的线程,它们就永远不会执行了。所以如果其他线程都进入了各自的等待队列(被阻塞),最后一个活动线程(拿到了锁或者还在同步队列中)调用了await方法但没有先解除另外某个线程的阻塞,现在这个线程也会阻塞。此时没有线程可以解除其他线程的阻塞状态,所以线程都挂起,程序gg。注意:只有当线程拥有一个条件的锁时,它才能在这个条件上调用await,singalAll或singal。
2)注意的一点是singalAll调用不会立即激活一个等待的线程。它只是解除等待线程的阻塞,使这些线程可以在当前线程释放锁之后竞争访问对象。

任务线程池的一个使用示例
package tacos.thread;

import org.junit.Test;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


public class ThreadDemo3 {

    @Test
    public void test() {
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1);
        scheduledThreadPool.schedule(new Thread3(), 3, TimeUnit.SECONDS);
        scheduledThreadPool.schedule(new Thread1(), 1, TimeUnit.SECONDS);
        scheduledThreadPool.schedule(new Thread6(), 6, TimeUnit.SECONDS);
        try {
            Thread.sleep(12000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        scheduledThreadPool.shutdown();
    }

    class Thread1 implements Runnable{

        @Override
        public void run() {
            System.out.println("延迟1s");
        }
    }

    class Thread3 implements Runnable{

        @Override
        public void run() {
            System.out.println("延迟3s");
        }
    }

    class Thread6 implements Runnable{

        @Override
        public void run() {
            System.out.println("延迟6s");
        }
    }
}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/4658540.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-06
下一篇 2022-11-06

发表评论

登录后才能评论

评论列表(0条)

保存