05 - 线程(三) 🗯️
线程同步案例-多线程放号器
public class NumberGen implements Runnable{
    private volatile static int num;
    private static RandomAccessFile raf;
    private boolean over;
    static{
        try {
            raf = new RandomAccessFile("day5-Thread/record.txt","rw");
            num = raf.readInt();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (EOFException e){
//            e.printStackTrace();
            System.out.println("当前没有号码记录,重新放号");
            num = 0;
        }catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void run() {
        while(!over){
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (this) {
                try {
                    num++;
                    System.out.println(Thread.currentThread().getName() + "获取号码:" + num);
                    //将文件指针设置到开头处
                    raf.seek(0);
                    //将当前号码记录到文件中
                    raf.writeInt(num);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public boolean isOver() {
        return over;
    }
    public void setOver(boolean over) {
        this.over = over;
    }
    public static void main(String[] args) {
        NumberGen ng = new NumberGen();
        Thread t1 = new Thread(ng,"放号机A");
        Thread t2 = new Thread(ng,"放号机B");
        Thread t3 = new Thread(ng,"放号机C");
        t1.start();
        t2.start();
        t3.start();
    }
}
线程的状态
概述
java 中的线程创建并启动之后不一定会一致持续执行,会根据程序的执行情况,存在各种不同的状态,之前了解操作系统中的线程分为 5 中状态(新建,就绪,执行,阻塞,死亡);但是 java 中对于线程有其他不同的解释,因此,java 中的线程状态在 Thread 类中有详细表述的。
Java 将线程分为六种状态:
| 状态 | 描述 | 
|---|---|
| NEW | 新建状态,该状态表示线程对象创建还未处于可运行状态 | 
| RUNNABLE | 可运行状态,线程处于准备运行或者正在被 JVM 进行调度执行的状态 | 
| BLOCKED | 锁阻塞状态,线程等待被其他线程占据的对象监视器释放 | 
| WATING | 无限等待,当执行以下对象的相关方法时:Object#wait(),Thread#join(),LockSuport#park() | 
| TIMED_WATING | 限时等待,当执行以下对象的相关方法时:Thread#sleep(long time),Object#wait(long time) | 
| TERMINATED | 中止状态,程序正常执行结束。线程销毁 | 
以上状态可以到 Thread.State 枚举类中找到:
public enum State {
    /**
         * Thread state for a thread which has not yet started.
         */
    NEW,
    /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
    RUNNABLE,
    /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
    BLOCKED,
    /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         */
    WAITING,
    /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
    TIMED_WAITING,
    /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
    TERMINATED;
}
Timed Wating(计时等待)
计时等待也称之为限时等待,即线程会执行一段时间的休眠,等待休眠时间到达,此时线程自动苏醒
sleep(long time)
public class TimedWatingDemo extends Thread{
    @Override
    public void run() {
        for (int i = 0;i < 100 ;i++){
            try {
                sleep(5000);
                System.out.println(getName()+"-->"+i);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
        new TimedWatingDemo().start();
    }
}
wait(long time)
public class TimedWatingDemo extends Thread {
    private Object obj = new Object();
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            synchronized (obj) {
                try {
                    obj.wait(5000);
                    System.out.println(getName() + "-->" + i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) {
        new TimedWatingDemo().start();
    }
}
sleep()和 wait()区别?
sleep:
- sleep()是Thread 类中提供一个方法,用于实现线程的限时休眠
- sleep()方法的执行不需要持有对象的监视器(不需要获取锁)
wait:
- wait 方法是来自Object 类中的方法,既可以实现线程的限时休眠,也可以实现线程的无限休眠
- wait 方法的使用必须持有对象的监视器,否则会出现
java.lang.IllegalMonitorStateException异常- wait 方法如果处于无限等待状态,则需要其他通过 notify 或 notifyAll 唤醒
- wait 方法的执行将会释放对象监视器
Blocked(锁阻塞)
该状态即一个线程处于等待其他线程释放对象锁的状态,例如死锁案例中:
if ("t1".equals(name)) {
    synchronized (o1) {
        System.out.println(name + "已锁定o1");
        //此时t1线程等待其他线程释放o2的对象锁
        synchronized (o2) {
            System.out.println(name + "执行完毕");
        }
    }
} else if ("t2".equals(name)) {
    synchronized (o2) {
        System.out.println(name + "已锁定o2");
        //此时t2线程等待其他线程释放o1的对象锁
        synchronized (o1) {
            System.out.println(name + "执行完毕");
        }
    }
}
Wating(无限等待)
当执行对象的某些特定方法时(如 Object 的 wait),会导致线程处于无限等待状态,即处于不确定何时能恢复执行,具体的恢复时间通常由其他线程进行控制(例如调用 Object 的 notify 或 notifyAll):
public class WaitDemo {
    public static void main(String[] args) {
        final Object obj = new Object();
        new Thread("线程A"){
            @Override
            public void run() {
                synchronized (obj){
                    System.out.println(getName()+"执行。。。已锁住obj");
                    try {
                        //线程A处于无限等待状态(同时会释放obj对象的对象监视器)
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("执行完毕");
                }
            }
        }.start();
        new Thread("线程B"){
            @Override
            public void run() {
                synchronized (obj) {
                    try {
                        Thread.sleep(5000);
                        //等待5秒之后,线程B会唤醒(同时释放obj对象的对象监视器)
                        obj.notify();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }
}
wait、notify、notifyAll
public static void main(String[] args) {
    final Object obj = new Object();
    final Object obj2 = new Object();
    new Thread("线程A"){
        @Override
        public void run() {
            synchronized (obj){
                System.out.println(getName()+"执行...已锁住obj");
                try {
                    obj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(getName()+"执行完毕");
            }
        }
    }.start();
    new Thread("线程C"){
        @Override
        public void run() {
            synchronized (obj){
                System.out.println(getName()+"执行...已锁住obj");
                try {
                    obj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(getName()+"执行完毕");
            }
        }
    }.start();
    new Thread("线程B"){
        @Override
        public void run() {
            synchronized (obj){
                try {
                    Thread.sleep(5000);
                    obj.notifyAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }.start();
}
- wait():方法的执行会导致当前线程处于无限等待状态,只有其他具备该对象监视器的对象执行 notify 或 notifyAll 时才能将其唤醒
- notify():唤醒等待当前对象的对象监视器的单个线程
- notifyAll():唤醒等待当前对象对象监视器的所有线程
生产者消费者问题
生产者消费者问题是线程中一个比较经典的案例,也成为有限缓冲区问题
