多线程学习笔记一

关于线程的常见问题-

  • 什么是并发与并行?

    1. 并行:两个或者多个事件在同一时刻发生
    2. 并发:两个或者多个事件在同一个时间段内发生
  • 什么是进程与线程?

    1. 进程是正在运行的程序的实例
    2. 进程是线程的容器,一个进程可以开启多个线程
    3. 比如打开一个浏览器,会创建进程
  • 线程如何创建?

    1. 继承Thread类
    2. 实现Runnable接口
    3. 实现Callable接口鸭
    4. 从线程池-Excutor 获取线程
  • 实现类接口和继承类接口的比较:
  1.   接口更适合多个相同的程序代码去共享同一个资源
  2.   接口可以避免java中单继承的局限性
  3.   接口代码可以被多个线程共享,代码和线程独立
  4.   线程池只能 放入实现Runnable和Callable接口的线程,不能直接放入继承Thread的线程
  5.   java中,每次运行程序至少启动2个线程,一个是main线程,一个是垃圾收集线程

 

  • 线程的生命周期?

 

  • 什么是线程安全问题?线程安全问题解决方案?
    • 线程安全问题都是由全局变量及静态变量引起的
    • 若每个线程对全局变量,静态变量只读,不写,则这个变量是线程安全的
    • 若有多个线程同时执行写操作,则需要考虑线程同步,否则就可能影响线程安全

    

    •  解决方案 :线程同步 - 只要在某个线程修改共享资源的时候,其他线程不能修改该资源,等待修改完毕同步之后,才能去抢夺资源,完成对应的操作,保证了数据的同步性。
    •  java引入了7种同步机制:
      • 同步代码块(synchronized)
      • 同步方法(synchronized)
      • 同步锁(ReentrantLock)
      • 特殊域变量(volatile)
      • 局部变量(ThreadLocal)
      • 阻塞队列(LinkedBlockingQueue)
      • 原子变量(Atomic*)

 

  • 什么是线程死锁?死锁的必要条件?如何避免死锁?

  

 

 

 

 

  • 线程如何通讯?
    • 多线程并发执行时,在默认情况下cpu是随机切换的,有时我们希望cpu按我们的规律执行线程,此时就需要线程之间的协调通信

    •  notify() & wait() 方法切换线程示例打印奇数偶数:
      •   
         1 public class ThreadTCPDemo {
         2     private int i = 0;
         3     private Object obj = new Object();
         4 
         5     public void odd() {
         6         // 判断是否小于10
         7         while (i < 10) {
         8             synchronized (obj) {
         9                 // 打印奇数
        10                 if (i % 2 == 1) {
        11                     System.out.println("奇数:" + i);
        12                     i++;
        13                     obj.notify(); // 唤醒偶数线程打印
        14                 } else {
        15                     try {
        16                         obj.wait(); // 等待偶数线程打印完毕
        17                     } catch (Exception e) {
        18                         e.printStackTrace();
        19                     }
        20                 }
        21             }
        22         }
        23     }
        24     public void even() {
        25         // 判断是否小于10
        26         while (i < 10) {
        27             synchronized (obj) {
        28                 // 打印奇数
        29                 if (i % 2 == 0) {
        30                     System.out.println("偶数:" + i);
        31                     i++;
        32                     obj.notify(); // 唤醒奇数线程打印
        33                 } else {
        34                     try {
        35                         obj.wait(); // 等待奇数线程打印完毕
        36                     } catch (Exception e) {
        37                         e.printStackTrace();
        38                     }
        39                 }
        40             }
        41         }
        42     }
        43     public static void main(String[] args) {
        44         final ThreadTCPDemo threadTCPDemo = new ThreadTCPDemo();
        45 
        46         Thread thread = new Thread(new Runnable() {
        47             @Override
        48             public void run() {
        49                 threadTCPDemo.odd();
        50             }
        51         });
        52         Thread thread2 = new Thread(new Runnable() {
        53             @Override
        54             public void run() {
        55                 threadTCPDemo.even();
        56             }
        57         });
        58         thread.start();
        59         thread2.start();
        60     }
        61 }
        View Code
    •  Condition 的signal()&await()方法切换线程示例打印奇数偶数:
      •   
         1 public class ThreadTCPDemo {
         2     private int i = 0;
         3     // private Object obj = new Object();
         4     private Lock lock = new ReentrantLock(false);
         5     private Condition condition = lock.newCondition();
         6 
         7     public void odd() {
         8         // 判断是否小于10
         9         while (i < 10) {
        10             lock.lock();  // 加锁
        11             try {
        12                 // 打印奇数
        13                 if (i % 2 == 1) {
        14                     System.out.println("奇数:" + i);
        15                     i++;
        16                     condition.signal(); // 唤醒偶数线程打印
        17                 } else {
        18                     try {
        19                         condition.await(); // 等待偶数线程打印完毕
        20                     } catch (Exception e) {
        21                         e.printStackTrace();
        22                     }
        23                 }
        24             } catch (Exception e) {
        25                 e.printStackTrace();
        26             } finally {
        27                 lock.unlock();
        28             }
        29         }
        30     }
        31 
        32     public void even() {
        33         // 判断是否小于10
        34         while (i < 10) {
        35             lock.lock();
        36             try {
        37                 // 打印偶数
        38                 if (i % 2 == 0) {
        39                     System.out.println("偶数:" + i);
        40                     i++;
        41                     condition.signal(); // 唤醒奇数线程打印
        42                 } else {
        43                     try {
        44                         condition.await(); // 等待奇数线程打印完毕
        45                     } catch (Exception e) {
        46                         e.printStackTrace();
        47                     }
        48                 }
        49             } catch (Exception e) {
        50                 e.printStackTrace();
        51             } finally {
        52                 lock.unlock();
        53             }
        54         }
        55     }
        56 
        57     public static void main(String[] args) {
        58         final ThreadTCPDemo threadTCPDemo = new ThreadTCPDemo();
        59 
        60         Thread thread = new Thread(new Runnable() {
        61             @Override
        62             public void run() {
        63                 threadTCPDemo.odd();
        64             }
        65         });
        66         Thread thread2 = new Thread(new Runnable() {
        67             @Override
        68             public void run() {
        69                 threadTCPDemo.even();
        70             }
        71         });
        72         thread.start();
        73         thread2.start();
        74     }
        75 }
        View Code 
    •  CountDownLatch 示例:
      
 1 public class CoachRacerDemo {
 2     // 设置要等待的运动员是3个
 3     private CountDownLatch countDownLatch = new CountDownLatch(3);
 4 
 5     /**
 6      *运动员方法,由运动员线程调用
 7      */
 8     public void racer(){
 9         // 获取运动员线程名称
10         String name = Thread.currentThread().getName();
11         // 运动员开始准备:打印准备信息
12         System.out.println(name+"正在准备。。。");
13         // 线程休眠1000毫秒,表示运动员在准备
14         try {
15             Thread.sleep(1000);
16         }catch (Exception e){
17             e.printStackTrace();
18         }
19         // 运动员准备完成
20         System.out.println(name+" 准备完毕!");
21         countDownLatch.countDown();
22     }
23 
24     /**
25      * 教练方法
26      */
27     public void coach() {
28         // 教练线程名称
29         String name = Thread.currentThread().getName();
30         // 教练等待所有的运动员准备完毕,打印等待信息
31         System.out.println(name+" 教练准备完毕。。。");
32         // 调用countDownLatch的await方法等待其他线程执行完毕
33         try {
34             countDownLatch.await();
35         }catch (Exception e){
36             e.printStackTrace();
37         }
38         // 所有运动员已就绪,教练开始训练,打印训练信息
39         System.out.println("所有运动员准备就绪,教练开始训练!");
40     }
41 
42     public static void main(String[] args) {
43 
44         // 创建运动员实例
45        final CoachRacerDemo coachRacerDemo =new CoachRacerDemo();
46         // 创建三个运动员线程对象
47         Thread thread1 = new Thread(new Runnable() {
48             @Override
49             public void run() {
50                 coachRacerDemo.racer();
51             }
52         },"运动员1");
53 
54         Thread thread2 = new Thread(new Runnable() {
55             @Override
56             public void run() {
57                 coachRacerDemo.racer();
58             }
59         },"运动员2");
60 
61         Thread thread3 = new Thread(new Runnable() {
62             @Override
63             public void run() {
64                 coachRacerDemo.racer();
65             }
66         },"运动员3");
67 
68         // 创建教练线程
69         Thread thread4 = new Thread(new Runnable() {
70             @Override
71             public void run() {
72                 coachRacerDemo.coach();
73             }
74         },"教练");
75         thread1.start();
76         thread2.start();
77         thread3.start();
78         thread4.start();
79     }
80 }
View Code
    •  CyclicBarrier 示例:
 1 public class ThreadCyclic {
 2     private CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
 3     public void startThread(){
 4         // 打印线程名称准备启动。。。
 5         String name = Thread.currentThread().getName();
 6         System.out.println(name+" 正在启动。。。");
 7         // 调用CyclicBarrier的await()方法等所有线程准备完成
 8         try {
 9             cyclicBarrier.await();
10         } catch (InterruptedException e) {
11             e.printStackTrace();
12         } catch (BrokenBarrierException e) {
13             e.printStackTrace();
14         }
15         // 打印启动信息
16         System.out.println(name+" 启动完毕。。。");
17     }
18     public static void main(String[] args) {
19         final ThreadCyclic threadCyclic = new ThreadCyclic();
20 
21         Thread thread =new Thread(new Runnable() {
22             @Override
23             public void run() {
24                 threadCyclic.startThread();
25             }
26         },"thread1");
27         Thread thread2 =new Thread(new Runnable() {
28             @Override
29             public void run() {
30                 threadCyclic.startThread();
31             }
32         },"thread2");
33         Thread thread3 =new Thread(new Runnable() {
34             @Override
35             public void run() {
36                 threadCyclic.startThread();
37             }
38         },"thread3");
39         thread.start();
40         thread2.start();
41         thread3.start();
42     }
43 }
View Code
    • Semaphore 示例(工人使用机器):   

    •  1 / 场景: 工人使用3台机器工作,机器为互斥资源(即每次只能一个人使用)
       2 public class SemaphoreTest {
       3 
       4    static class Work implements Runnable{
       5         private int workerNo; // 工人工号
       6         private Semaphore semaphore;  // 机器数
       7 
       8        public Work(int workerNo, Semaphore semaphore) {
       9            this.workerNo = workerNo;
      10            this.semaphore = semaphore;
      11        }
      12        @Override
      13        public void run() {
      14 
      15            try{
      16                // 1. 工人获取机器
      17                semaphore.acquire();
      18                String name = Thread.currentThread().getName();
      19                // 2. 打印工人获取到机器,开始工作
      20                System.out.println(name+" - 获取到机器开始工作。。。");
      21                // 3. 给线程睡眠1秒,模拟工人使用机器
      22                Thread.sleep(1000);
      23                // 4. 使用完毕释放机器,打印工人使用完毕,释放机器
      24                System.out.println(name+" - 使用完毕,释放机器!");
      25                semaphore.release();
      26            }catch (Exception e){
      27                e.printStackTrace();
      28            }
      29 
      30        }
      31    }
      32     public static void main(String[] args) {
      33        int workers = 8;
      34        Semaphore semaphore = new Semaphore(3);
      35        for (int i=0;i<workers;i++){
      36         new Thread(new Work(i, semaphore),"工人"+i).start();
      37        }
      38     }
      39 }
      View Code

面试题 : sleep 和wait方法的区别 ?

 

面试题 : notify 和wait方法的区别 ?

 

posted @ 2020-04-07 01:51  二先森  阅读(113)  评论(0编辑  收藏  举报