Java并发编程之Thread

1、线程状态

 public enum State {
 		/**
 		 * 创建状态
 		 * 尚未启动的新线程处于此状态
 		 */
		NEW,
		
        /**
         * 可运行状态
         * 处于可运行状态的线程正在Java虚拟机中执行,但它可能正在等待来自操作系统的其他资源,例如处理器
         */
        RUNNABLE,        
		
		/**
 		 * 阻塞状态
 		 * 等待监视器锁定而被阻塞的线程处于此状态
 		 * 处于阻塞状态的线程正在等待监视器锁进入同步块/方法,或在调用后重新进入同步块/方法
 		 */
        BLOCKED,
        
        /**
 		 * 无限等待状态
 		 * 正在无限期等待另一个线程执行特定操作的线程处于这种状态
 		 * Object.wait with no timeout
 		 * Thread.join with no timeout
 		 */
        WAITING,
        
        /**
 		 * 超时等待状态
 		 * 等待另一个线程在指定等待时间内执行操作的线程处于此状态
 		 * Thread.sleep
 		 * Object.wait with timeout
 		 * Thread.join with timeout
 		 */
        TIMED_WAITING,
        
        /**
 		 * 终止状态
 		 * 线程已完成执行,终止已退出的线程处于此状态
 		 */
        TERMINATED;
    }

2、线程优先级

	//priority参数表示优先级
    private int  priority;
	//最小优先级
    public final static int MIN_PRIORITY = 1;
    //默认优先级
    public final static int NORM_PRIORITY = 5;
    //最大优先级
    public final static int MAX_PRIORITY = 10;

    public final void setPriority(int newPriority) {
        ThreadGroup g;
        checkAccess();
        if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
            throw new IllegalArgumentException();
        }
        if((g = getThreadGroup()) != null) {
            if (newPriority > g.getMaxPriority()) {
                newPriority = g.getMaxPriority();
            }
            setPriority0(priority = newPriority);
        }
    }

	public final int getPriority() {
        return priority;
    }

优先级越高先执行机会越大,但不一定先执行。

3、创建线程

继承 Thread,重写run()方法

    static class MyThread extends Thread {

        public MyThread(String name) {
            super(name);
        }

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

	private static void demo01() {
        MyThread t1 = new MyThread("t1");
        t1.start();
    }

实现 Runable,重写run()方法,需要Thread类来包装

    static class MyThread2 implements Runnable {

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

	private static void demo01() {
        Thread t2 = new Thread(new MyThread2(), "t2");
        t2.start();

		//匿名内部类
        Thread t22 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程:" + Thread.currentThread().getName() + " 开始执行!!!");
            }
        }, "t22");
        t22.start();

		//Lamda表达式
		Thread t23 = new Thread(() -> System.out.println("线程:" + Thread.currentThread().getName() + " 开始执行!!!"), "t23");
        t23.start();
    }

实现 Callable,重写call()方法,然后包装成java.util.concurrent.FutureTask, 再然后包装成Thread

    static class MyThread3 implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            System.out.println("线程:" + Thread.currentThread().getName() + " 开始执行!!!");
            return 1;
        }
    }

    private static void demo01() throws ExecutionException, InterruptedException {
        MyThread3 callable = new MyThread3();
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        Thread t3 = new Thread(futureTask, "t3");
        t3.start();
        System.out.println("futureTask = " + futureTask.get());
    }

Thread: 继承方式, 不建议使用, 因为Java是单继承的,继承了Thread就没办法继承其它类了,不够灵活
Runnable: 实现接口,比Thread类更加灵活,没有单继承的限制
Callable: Thread和Runnable都是重写的run()方法并且没有返回值,Callable是重写的call()方法并且有返回值并可以借助FutureTask类来判断线程是否已经执行完毕或者取消线程执行

4、start() 和 run()

	Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程:" + Thread.currentThread().getName() + " 开始执行!!!");
            }
        }, "t1");
        t1.run();

	Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程:" + Thread.currentThread().getName() + " 开始执行!!!");
            }
        }, "t2");
        t2.start();

run():线程运行时执行的代码块,业务逻辑就写在run方法中;直接调用run方法,仍是main线程执行,而不是由新的线程执行。
start():启动一个线程,Java 虚拟机调用该线程的 run 方法。

5、interrupt() 线程中断

interrupt() :中断本线程(将中断状态标记为true)
isInterrupted():测试当前线程是否已中断。此方法不会影响线程的中断状态。
interrupted() :测试当前线程是否已中断。此方法清除线程的中断状态。换句话说,如果这个方法被连续调用两次,第二次调用将返回false(除非当前线程在第一次调用清除其中断状态之后,第二次调用检查之前再次中断)

    public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();

        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           // Just to set the interrupt flag
                b.interrupt(this);
                return;
            }
        }
        interrupt0();
    }

    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }

    public boolean isInterrupted() {
        return isInterrupted(false);
    }

    private native boolean isInterrupted(boolean ClearInterrupted);

6、join() 线程加入

父线程等待子线程的终止。
也就是说父线程的代码块中,如果碰到了子线程的join()方法,此时父线程需要等待(阻塞),等待子线程结束了,才能继续执行join()之后的代码块。

    public final void join() throws InterruptedException {
        join(0);
    }

	public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

示例 join

    private static void demo02() {
        Thread t1 = new Thread(() -> {
            System.out.println("线程:" + Thread.currentThread().getName() + " >> ready");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程:" + Thread.currentThread().getName() + " >> over");
        }, "t1");

        t1.start();
        try {
            System.out.println("main线程等待t1线程执行");
            t1.join();
            // 带参数,则main线程等待一段时间,超时就不理子线程了自己继续执行
            // t1.join(3000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("main线程执行完毕");

    }

在这里插入图片描述

7、yield() 线程礼让

交出CPU的执行时间,不会释放锁,让线程进入就绪状态,等待重新获取CPU执行时间

		Thread t1 = new Thread(() -> System.out.println("线程:" + Thread.currentThread().getName() + " 开始执行!!!" ), "t1");
        t1.start();

        while (Thread.activeCount() > 1) Thread.yield();
        System.out.println("线程礼让,子线程跑完,主线程才跑");

8、wait() 和 notify()、notifyAll()

1.wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。“直到其他线程调用此对象的notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”)
2.notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程;notify()是唤醒单个线程,而notifyAll()是唤醒所有的线程。
3.wait(long timeout)让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的notify()方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。

注意:
wait()、notify()和notifyAll()都需要在synchronized作用范围中使用
因为wait()方法调用时,会释放线程获得的锁(也就是说当前线程必须持有锁),wait()方法返回后,线程又会重新试图获得锁。

示例 wait

	//对象锁
	private static final ThreadDemo demo = new ThreadDemo();

    private static void demo03() {
        Thread t1 = new Thread(demo::method03, "t1");
        Thread t2 = new Thread(demo::method031, "t2");

        t1.start();
        t2.start();
    }

    private void method03() {
        String name = Thread.currentThread().getName();
        System.out.println("线程:" + name + " is ready");
        try {
            Thread.sleep(10);
            synchronized (demo) {
                System.out.println("线程:" + name + "--> 获取锁");
                Thread.sleep(3000);
                System.out.println("线程:" + name + "--> 执行wait方法,线程挂起,释放锁,等待被唤醒");
                demo.wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程:" + name + " is over");
    }

    private void method031() {
        String name = Thread.currentThread().getName();
        System.out.println("线程:" + name + " is ready");
        try {
            Thread.sleep(50);
            synchronized (demo) {
                System.out.println("线程:" + name + "--> 获取锁");
                Thread.sleep(3000);
                System.out.println("线程:" + name + "--> 执行notifyAll方法,唤醒其他线程并调用wait方法使自己挂起");
                demo.notifyAll();
            }
            //执行同步代码块后自动释放锁
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程:" + name + " is over");
    }

在这里插入图片描述

示例 wait 2

    // 定义生产最大量
    private int productCount = 0;

    private static void demo04() {
        // 创建t1线程,生产资源
        Thread t1 = new Thread(demo::demo04_product, "t1");
        // 创建t2线程,消费资源
        Thread t2 = new Thread(demo::demo04_customer, "t2");
        Thread t3 = new Thread(demo::demo04_customer, "t3");

        // 启动线程
        t1.start();
        t2.start();
        t3.start();
    }

    private synchronized void demo04_product() {
        try {
            while (true) {
                System.out.println(Thread.currentThread().getName() + ":::生产:::" + (++productCount));
                Thread.sleep(300);
                if (productCount >= 20) {
                    System.out.println("货舱已满...不必再生产");
                    notifyAll();
                    wait();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private synchronized void demo04_customer() {
        try {
            while (true) {
                System.out.println(Thread.currentThread().getName() + ":::消费:::" + productCount);
                Thread.sleep(300);
                if (productCount <= 1) {
                    productCount = 0;
                    System.out.println("货舱已无货...无法消费");
                    notifyAll();
                    wait();
                } else productCount--;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

在这里插入图片描述

9、sleep() 和 wait()

sleep是Thread的方法;wait是Object的方法
sleep必须指定时间;wait可以指定也可以不用
sleep可以在任意地方使用;wait在能synchronized范围内使用
sleep释放CPU执行权,但不释放同步锁;wait释放CPU执行权,也释放同步锁,使得其他线程可以使用同步控制块或者方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值