• 创建线程两种方法:扩展Thread 类 ;实现Runnable 接口 。
    • Thread.States的线程状态:NEW、RUNNABLE、BLOCKED、WAITING、TIME_WAITING、TERMINATED
    • 操作系统线程状态:创建状态 、就绪状态 、运行状态 、阻塞状态 、死亡状态
    • callable区别:

      • 接口。有简单类型参数,与call()方法的返回类型相对应。
      • 声明了call()方法。执行器运行任务时,该方法会被执行器执行。它必须返回声明中指定类型的对象。
      • call()方法可以抛出任何一种校验异常。可以实现自己的执行器并重载afterExecute()方法来处
        理这些异常 。
    • callable代码示例: ```java // 有泛型、有返回值 class MyCallable implements Callable { @Override public String call() throws Exception {

      1. Thread.sleep(5000);
      2. return "hello world call() invoked!";

      } }

    public class Main { public static void main(String[] args) throws ExecutionException,InterruptedException { MyCallable myCallable = new MyCallable(); // 设置Callable对象,泛型表示Callable的返回类型 FutureTask futureTask = new FutureTask(myCallable); // 启动处理线程 new Thread(futureTask).start(); // 同步等待线程运行的结果 String result = futureTask.get(); // 5s后得到结果 System.out.println(result); } }

    1. - 锁对象的作用
    2. > 1. 这个对象内部得有一个标志位(state变量),记录自己有没有被某个线程占用。最简单的情况是这个state有0、1两个取值,0表示没有线程占用这个锁,1表示有某个线程占用了这个锁。
    3. > 2. 如果这个对象被某个线程占用,记录这个线程的thread ID。
    4. > 3. 这个对象维护一个thread id list,记录其他所有阻塞的、等待获取拿这个锁的线程。在当前线程释放锁之后从这个thread id list里面取一个线程唤醒。
    5. - 锁如何实现
    6. > 在对象头里,有一块数据叫Mark Word。在64位机器上,Mark Word是8字节(64位)的,这64位中有2个重要字段:锁标志位和占用该锁的thread ID。因为不同版本的JVM实现,对象头的数据结构会有各种差异。
    7. - 实现生产者消费者思路
    8. > 1. 内存队列本身要加锁,才能实现线程安全。(必须实现)
    9. > 2. 阻塞。当内存队列满了,生产者放不进去时,会被阻塞;当内存队列是空的时候,消费者无事可做,会被阻塞。
    10. > 3. 双向通知。消费者被阻塞之后,生产者放入新数据,要notify()消费者;反之,生产者被阻塞之后,消费者消费了数据,要notify()生产者。
    11. >
    12. > - 如何阻塞
    13. > - 线程自己阻塞自己,也就是生产者、消费者线程各自调用wait()和notify()。
    14. > - 用一个阻塞队列,当取不到或者放不进去数据的时候,入队/出队函数本身就是阻塞的。
    15. > - 如何双向通知?
    16. > - wait()与notify()机制。
    17. > - Condition机制。
    18. // 单个生产者和消费者的情况
    19. ```java
    20. // 我的理解: 重点是先把阻塞队列实现了,剩下的都好说.jpg
    21. // 阻塞队列
    22. public class MyQueue {
    23. private String[] data = new String[10];
    24. private int getIndex = 0;
    25. private int putIndex = 0;
    26. private int size = 0;
    27. public synchronized void put(String element) {
    28. if (size == data.length) {
    29. try {
    30. wait();
    31. } catch (InterruptedException e) {
    32. e.printStackTrace();
    33. }
    34. }
    35. data[putIndex] = element;
    36. ++putIndex;
    37. if (putIndex == data.length) putIndex = 0;
    38. ++size;
    39. notify();
    40. }
    41. public synchronized String get() {
    42. if (size == 0) {
    43. try {
    44. wait();
    45. } catch (InterruptedException e) {
    46. e.printStackTrace();
    47. }
    48. }
    49. String result = data[getIndex];
    50. ++getIndex;
    51. if (getIndex == data.length) getIndex = 0;
    52. --size;
    53. notify();
    54. return result;
    55. }
    56. }
    57. public class Main {
    58. public static void main(String[] args) {
    59. MyQueue myQueue = new MyQueue();
    60. ProducerThread producerThread = new ProducerThread(myQueue);
    61. ConsumerThread consumerThread = new ConsumerThread(myQueue);
    62. producerThread.start();
    63. consumerThread.start();
    64. }
    65. }
    66. // 生产者
    67. public class ProducerThread extends Thread {
    68. private final MyQueue myQueue;
    69. private final Random random = new Random();
    70. private int index = 0;
    71. public ProducerThread(MyQueue myQueue) {
    72. this.myQueue = myQueue;
    73. }
    74. @Override
    75. public void run() {
    76. while (true) {
    77. String tmp = "ele-" + index;
    78. myQueue.put(tmp);
    79. System.out.println("添加元素:" + tmp);
    80. index++;
    81. try {
    82. Thread.sleep(random.nextInt(1000));
    83. } catch (InterruptedException e) {
    84. e.printStackTrace();
    85. }
    86. }
    87. }
    88. }
    89. // 消费者
    90. public class ConsumerThread extends Thread {
    91. private final MyQueue myQueue;
    92. private final Random random = new Random();
    93. public ConsumerThread(MyQueue myQueue) {
    94. this.myQueue = myQueue;
    95. }
    96. @Override
    97. public void run() {
    98. while (true) {
    99. String s = myQueue.get();
    100. System.out.println("\t\t消费元素:" + s);
    101. try {
    102. Thread.sleep(random.nextInt(1000));
    103. } catch (InterruptedException e) {
    104. e.printStackTrace();
    105. }
    106. }
    107. }
    108. }

    // 多个消费者和生产者 Ps感觉不太对。。。。
    // notify 唤醒的可能还是生产者,感觉用到Condition
    // 把if改成whire

    1. public class MyQueue2 {
    2. private String[] data = new String[10];
    3. private int getIndex = 0;
    4. private int putIndex = 0;
    5. private int size = 0;
    6. public synchronized void put(String element) {
    7. //if (size == data.length) {
    8. while (size == data.length) {
    9. try {
    10. wait();
    11. } catch (InterruptedException e) {
    12. e.printStackTrace();
    13. }
    14. put(element);
    15. } else {
    16. put0(element);
    17. notify();
    18. }
    19. }
    20. private void put0(String element) {
    21. data[putIndex] = element;
    22. ++putIndex;
    23. if (putIndex == data.length) putIndex = 0;
    24. ++size;
    25. }
    26. public synchronized String get() {
    27. // if (size == 0) {
    28. while (size == 0) {
    29. try {
    30. wait();
    31. } catch (InterruptedException e) {
    32. e.printStackTrace();
    33. }
    34. return get();
    35. } else {
    36. String result = get0();
    37. notify();
    38. return result;
    39. }
    40. }
    41. private String get0() {
    42. String result = data[getIndex];
    43. ++getIndex;
    44. if (getIndex == data.length) getIndex = 0;
    45. --size;
    46. return result;
    47. }
    48. }
    • 伪代码:生产消费线程 ```java public void enqueue() {

      1. synchronized (queue) {
      2. while (queue.full()) {
      3. queue.wait();
      4. } //... 数据入列
      5. queue.notify(); // 通知消费者,队列中有数据了。
      6. }

      }

      public void dequeue() {

      1. synchronized (queue) {
      2. while (queue.empty()) {
      3. queue.wait();
      4. } // 数据出队列
      5. queue.notify(); // 通知生产者,队列中有空间了,可以继续放数据了。
      6. }

      }

    ```

    • InterruptedException

      如果不是那些显示捕获这个异常的方法,那么不会抛出异常

      thread.interrupted()的精确含义是“唤醒轻量级阻塞”,而不是字面意思“中断一个线程”。

    • 轻量级阻塞和重量级阻塞

    image.png

    • 关于interrupt

      thread.isInterrupted()与Thread.interrupted()的区别因为 thread.interrupted()相当于给线程发送了一个唤醒的信号,所以如果线程此时恰好处于WAITING或者TIMED_WAITING状态,就会抛出一个InterruptedException,并且线程被唤醒。而如果线程此时并没有被阻塞,则线程什么都不会做。但在后续,线程可以判断自己是否收到过其他线程发来的中断信号,然后做一些对应的处理。
      这两个方法都是线程用来判断自己是否收到过中断信号的,前者是实例方法,后者是静态方法。二
      者的区别在于,前者只是读取中断状态,不修改状态;后者不仅读取中断状态,还会重置中断标志位。

    • thread.isInterrupted()与Thread.interrupted()的区别