多线程学习笔记一
关于线程的常见问题-
-
什么是并发与并行?
- 并行:两个或者多个事件在同一时刻发生
- 并发:两个或者多个事件在同一个时间段内发生
-
什么是进程与线程?
- 进程是正在运行的程序的实例
- 进程是线程的容器,一个进程可以开启多个线程
- 比如打开一个浏览器,会创建进程
-
线程如何创建?
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口鸭
- 从线程池-Excutor 获取线程
- 实现类接口和继承类接口的比较:
- 接口更适合多个相同的程序代码去共享同一个资源
- 接口可以避免java中单继承的局限性
- 接口代码可以被多个线程共享,代码和线程独立
- 线程池只能 放入实现Runnable和Callable接口的线程,不能直接放入继承Thread的线程
- 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 }
-
- 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 }
-
- CountDownLatch 示例:
- notify() & wait() 方法切换线程示例打印奇数偶数:
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 }
-
- 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 }
-
-
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 }
-
面试题 : sleep 和wait方法的区别 ?
面试题 : notify 和wait方法的区别 ?