ToB企服应用市场:ToB评测及商务社交产业平台

标题: java多线程 [打印本页]

作者: 刘俊凯    时间: 2023-5-29 09:13
标题: java多线程
java多线程

进程、线程与多线程

线程的三种创建方式

通过继承Thread创建线程

​        注意:Thread类实现了Runnable接口
流程:
  1. 1. 自定义线程类继承Thread类
  2. 2. 重写其run()方法,编写程序执行体
  3. 3. 创建线程对象,调用start()方法启动线程
复制代码
  1. public class MyThread extends Thread {
  2.     @Override
  3.     public void run() {
  4.         //run方法线程体
  5.         for (int i = 0; i < 5; i++) {
  6.             System.out.println("run方法线程--"+i);
  7.         }
  8.     }
  9.     public static void main(String[] args) {
  10.         //run方法线程
  11.         MyThread myThread = new MyThread();
  12.         //启动线程,另外线程只能启动一次死亡之后不能重新启动
  13.         myThread.start();
  14.         //主线程
  15.         for (int i = 0; i < 5; i++) {
  16.             System.out.println("主线程--"+i);
  17.         }
  18.     }
  19. }
  20. /*out:
  21. 主线程--0
  22. run方法线程--0
  23. 主线程--1
  24. run方法线程--1
  25. 主线程--2
  26. run方法线程--2
  27. 主线程--3
  28. run方法线程--3
  29. 主线程--4
  30. run方法线程--4
  31. 注意:输出结果不唯一,每次执行结果不一样
  32. 线程开启不一定立即执行,是由cpu调度执行
复制代码
实现Runnable接口创建线程
  1. 1. 自定义线程类实现Runnable接口
  2. 2. 重写其run()方法,编写程序执行体
  3. 3. 创建该实现类对象,创建Thread线程对象(或者创建Thread对象),并且向Thread对象丢入Runnable实现类(代理方法)
复制代码
  1. public class MyThread implements  Runnable {
  2.     @Override
  3.     public void run() {
  4.         //run方法线程体
  5.         for (int i = 0; i < 5; i++) {
  6.             System.out.println("run方法线程--"+i);
  7.         }
  8.     }
  9.     public static void main(String[] args) {
  10.         //run方法线程
  11.         MyThread myThread = new MyThread();
  12.         //静态代理
  13.         new Thread(myThread).start();
  14.         //主线程
  15.         for (int i = 0; i < 5; i++) {
  16.             System.out.println("主线程--"+i);
  17.         }
  18.     }
  19. }
  20. /*
  21. 主线程--0
  22. run方法线程--0
  23. 主线程--1
  24. run方法线程--1
  25. 主线程--2
  26. 主线程--3
  27. run方法线程--2
  28. 主线程--4
  29. run方法线程--3
  30. run方法线程--4
复制代码
相比于前一种更推荐本方法:避免单继承局限,灵活方便,方便一个对象被多个线程使用
例如:
  1. public class MyThread implements  Runnable {
  2.     private  int number=10;
  3.     @Override
  4.     public void run() {
  5.        while (true){
  6.            if(number<=0){
  7.                break;
  8.            }
  9.            //线程休眠,防止cpu速度太快瞬间把票抢完
  10.            try {
  11.                Thread.sleep(10);
  12.            } catch (InterruptedException e) {
  13.                e.printStackTrace();
  14.            }
  15. //当前线程名字
  16.            System.out.println(Thread.currentThread().getName()+"--"+number--);
  17.        }
  18.     }
  19.     public static void main(String[] args) {
  20.         //run方法线程
  21.         MyThread myThread = new MyThread();
  22.         //第二个参数为线程名字
  23.         new Thread(myThread,"李").start();
  24.         new Thread(myThread,"马").start();
  25.         new Thread(myThread,"王").start();
  26.     }
  27. }
  28. /*
  29. 马--9
  30. 王--10
  31. 李--10
  32. 马--8
  33. 李--8
  34. 王--8
  35. 马--7
  36. 王--6
  37. 李--6
  38. 王--5
  39. 马--4
  40. 李--3
  41. 李--0
  42. 马--2
  43. 王--1
  44. 注意:至于为什么出现两个人得到同一个数字,或者出现0,则是一些经典的线程同步问题
复制代码
线程的五大状态



线程方法


停止线程

  1. //<>中填写返回值类型(下面call方法的返回值)
  2. public class MyThread implements Callable<Boolean> {
  3.     //重写call方法,返回值保持和<>中的一样
  4.     @Override
  5.     public Boolean call() throws Exception {\
  6.         //具体线程操作写在这里
  7.         return false;
  8.     }
  9.     public static void main(String[] args) throws ExecutionException, InterruptedException {
  10.         MyThread myThread1 = new MyThread();
  11.         MyThread myThread2 = new MyThread();
  12.         MyThread myThread3 = new MyThread();
  13.         //创建执行服务:newFixedThreadPool线程池,参数为线程池大小
  14.         ExecutorService ser = Executors.newFixedThreadPool(3);
  15.         //提交执行:<>中类型就是call的返回类型
  16.         Future<Boolean> r1 = ser.submit(myThread1);
  17.         Future<Boolean> r2 = ser.submit(myThread2);
  18.         Future<Boolean> r3 = ser.submit(myThread3);
  19.         //获取结果:call()返回值
  20.         Boolean rs1 = r1.get();
  21.         Boolean rs2 = r2.get();
  22.         Boolean rs3 = r3.get();
  23.         //关闭服务
  24.         ser.shutdownNow();
  25.     }
  26. }
复制代码
线程休眠

没啥可说的固定写法:Thread.sleep()
线程礼让

  1.         //MyThread是Runnable接口的实现类
  2.         MyThread myThread = new MyThread();
  3.         //静态代理
  4.         new Thread(myThread).start();
复制代码
线程强制执行

  1. public interface MyInterface {
  2.     void lambda();
  3. }
  4. class main {
  5.     public static void main(String[] args) {
  6. //        无参且一行
  7.         MyInterface myInterface =() -> System.out.println("hello world");
  8. //        有参数a
  9. //        MyInterface myInterface =a  -> System.out.println("hello world");
  10. //        多行
  11. //        MyInterface myInterface1 = ()->{
  12. //            System.out.println();
  13. //            System.out.println()
  14. //        };
  15.         
  16. //        上述代码完全类似下面的匿名内部类
  17. //        MyInterface myInterface1 = new MyInterface() {
  18. //            @Override
  19. //            public void lambda() {
  20. //                System.out.println("hello world");
  21. //            }
  22. //        };
  23.     }
  24. }
  25. //out:hello world
复制代码
线程状态观测

  1. public class MyThread implements  Runnable {
  2.     private boolean flag = true;
  3.     @Override
  4.     public void run() {
  5.         int i = 0;
  6.         while (flag){
  7.             System.out.println("run........Thread"+i++);
  8.         }
  9.     }
  10.     public void stop(){
  11.         this.flag = false;
  12.         System.out.println("线程已经停止");
  13.     }
  14.     public static void main(String[] args) {
  15.         MyThread myThread = new MyThread();
  16.         new Thread(myThread).start();
  17.         for (int i = 0; i < 10; i++) {
  18.             //不加这一句的话循环速度太快以至于线程还没运行
  19.             System.out.println("main---"+i);
  20.             if(i==5){
  21.                 //调用自己写的stop方法
  22.                 myThread.stop();
  23.             }
  24.         }
  25.     }
  26. }
  27. /*
  28. main---0
  29. run........Thread0
  30. main---1
  31. run........Thread1
  32. main---2
  33. run........Thread2
  34. main---3
  35. run........Thread3
  36. main---4
  37. run........Thread4
  38. main---5
  39. run........Thread5
  40. 线程已经停止
  41. main---6
  42. main---7
  43. main---8
  44. main---9
复制代码
线程优先级

  1. public class MyThread implements  Runnable {
  2.     private boolean flag = true;
  3.     @Override
  4.     public void run() {
  5.         System.out.println(Thread.currentThread().getName()+"开始执行");
  6.         Thread.yield();
  7.         System.out.println(Thread.currentThread().getName()+"完成执行");
  8.     }
  9.     public static void main(String[] args) {
  10.         MyThread myThread = new MyThread();
  11.         MyThread myThread1 = new MyThread();
  12.         new Thread(myThread,"a").start();
  13.         new Thread(myThread1,"b").start();
  14.     }
  15. }
  16. /*
  17. a开始执行
  18. b开始执行
  19. b完成执行
  20. a完成执行
复制代码
守护线程

  1. public class MyThread implements  Runnable {
  2.     @Override
  3.     public void run() {
  4.         for (int i = 0; i < 5; i++) {
  5.             System.out.println("VIP驾到通通闪开!"+i);
  6.         }
  7.     }
  8.     public static void main(String[] args) throws InterruptedException {
  9.         MyThread myThread1 = new MyThread();
  10.         Thread thread1 = new Thread(myThread1, "vip");
  11.         //主线程
  12.         for (int i = 0; i < 10; i++) {
  13.             if(i==5){
  14.                 thread1.start();
  15.                 thread1.join();
  16.             }
  17.             System.out.println("我是一个主线程"+i);
  18.         }
  19.     }
  20. }
  21. /*
  22. 我是一个主线程0
  23. 我是一个主线程1
  24. 我是一个主线程2
  25. 我是一个主线程3
  26. 我是一个主线程4
  27. VIP驾到通通闪开!0
  28. VIP驾到通通闪开!1
  29. VIP驾到通通闪开!2
  30. VIP驾到通通闪开!3
  31. VIP驾到通通闪开!4
  32. 我是一个主线程5
  33. 我是一个主线程6
  34. 我是一个主线程7
  35. 我是一个主线程8
  36. 我是一个主线程9
复制代码
线程同步


线程同步操作多种不安全问题,具体可以看上面实现Runnable接口创建线程的例子
synchronized(锁)

使用同步方法解决问题:
  1.     public static void main(String[] args) throws InterruptedException {
  2.         Thread thread = new Thread(() -> {
  3.             for (int i = 0; i < 5; i++) {
  4.                 try {
  5.                     Thread.sleep(1000);
  6.                 } catch (InterruptedException e) {
  7.                     e.printStackTrace();
  8.                 }
  9.             }
  10.             System.out.println("////////");
  11.         });
  12.         //观测状态
  13.         Thread.State state = thread.getState();
  14.         System.out.println(state);
  15. //        启动线程
  16.         thread.start();
  17.         state = thread.getState();
  18.         System.out.println(state);
  19. //        只要线程不终止一直输出状态
  20.         while (state != Thread.State.TERMINATED){
  21.             Thread.sleep(1000);
  22.             state = thread.getState();
  23.             System.out.println(state);
  24.         }
  25.     }
  26. /*
  27. NEW
  28. RUNNABLE
  29. RUNNABLE
  30. TIMED_WAITING
  31. TIMED_WAITING
  32. RUNNABLE
  33. TIMED_WAITING
  34. ////////
  35. TERMINATED
复制代码
锁块:
  1. public class MyThread implements  Runnable {
  2.     @Override
  3.     public void run() {
  4.         try {
  5.             Thread.sleep(1000);
  6.         } catch (InterruptedException e) {
  7.             e.printStackTrace();
  8.         }
  9.         System.out.println(Thread.currentThread().getName());
  10.     }
  11.     public static void main(String[] args) throws InterruptedException {
  12.         //主线程优先级:主线程优先级无法修改
  13.         System.out.println(Thread.currentThread().getName()+"-----"+Thread.currentThread().getPriority());
  14.         MyThread myThread = new MyThread();
  15.         Thread t1 = new Thread(myThread,"t1");
  16.         Thread t2 = new Thread(myThread,"t2");
  17.         Thread t3 = new Thread(myThread,"t3");
  18.         Thread t4 = new Thread(myThread,"t4");
  19.         Thread t5 = new Thread(myThread,"t5");
  20. //        一定要注意:先设置优先级再启动否则没用
  21.         t1.start();
  22.         t2.setPriority(1);
  23.         t2.start();
  24.         //设置为最大优先级
  25.         t3.setPriority(Thread.MAX_PRIORITY);
  26.         t3.start();
  27.     }
  28. }
  29. /*
  30. main-----5
  31. t3
  32. t2
  33. t1
复制代码
CopyOnWriteArrayList
  1. Thread thread = new Thread();
  2. //默认是false代表用户线程,设置为true表示守护线程
  3. thread.setDaemon(true);
复制代码
死锁

多个线程各自占有一些共享资源,同时互相等待对方占有资源,从而导致两个或多个线程都在等待对方释放资源停止执行的情况。
某一个同步块同时拥有两个以上对象的锁,就可能出现死锁
  1. public class MyThread implements  Runnable {
  2.     private  int number=10;
  3.     private  boolean flag = true;
  4.     @Override
  5.     public  void run() {
  6.         while (flag) {
  7.             try {
  8.                 Thread.sleep(1000);
  9.             } catch (InterruptedException e) {
  10.                 e.printStackTrace();
  11.             }
  12.             buy();
  13.         }
  14.     }
  15.     //上锁,run方法也可以锁
  16.     public synchronized void buy() {
  17.         if (number < 1) {
  18.             flag=false;
  19.             return;
  20.         }
  21.             System.out.println(Thread.currentThread().getName() + "--" + number--);
  22.         }
  23.     public static void main(String[] args) {
  24.         MyThread myThread = new MyThread();
  25.         new Thread(myThread,"李").start();
  26.         new Thread(myThread,"马").start();
  27.         new Thread(myThread,"王").start();
  28.     }
  29. }
  30. /*
  31. 李--10
  32. 王--9
  33. 马--8
  34. 马--7
  35. 李--6
  36. 王--5
  37. 马--4
  38. 李--3
  39. 王--2
  40. 马--1
复制代码
产生死锁的必要条件

Lock(锁)

  1. public class MyThread implements  Runnable {
  2.     private  int number=10;
  3.     private  boolean flag = true;
  4.     @Override
  5.     public  void run() {
  6.         while (flag) {
  7.             try {
  8.                 Thread.sleep(1000);
  9.             } catch (InterruptedException e) {
  10.                 e.printStackTrace();
  11.             }
  12.             //同步块,()填变化的量必须是引用类型,锁定的就是传入参数
  13.             synchronized (Integer.valueOf(number)){
  14.                 if (number < 1) {
  15.                     flag=false;
  16.                 }
  17.                 else {
  18.                     System.out.println(Thread.currentThread().getName() + "--" + number--);
  19.                 }
  20.             }
  21.             }
  22.         }
  23.     public static void main(String[] args) {
  24.         MyThread myThread = new MyThread();
  25.         new Thread(myThread,"李").start();
  26.         new Thread(myThread,"马").start();
  27.         new Thread(myThread,"王").start();
  28.     }
  29. }
  30. /*
  31. 马--10
  32. 王--9
  33. 李--8
  34. 李--7
  35. 王--6
  36. 马--5
  37. 马--4
  38. 李--3
  39. 王--2
  40. 马--1
复制代码
线程协作--生产者消费者问题

生产者消费者问题:生产者消费者共享一个资源,并且生产者和消费者之间相互依赖,互为条件,操作系统学过的不想多说具体如下:

下面两个解决办法后面有具体演示
解决方法1:

解决方法二:信号灯法
java提供了几个方法解决线程之间的通信问题:
注意:以下均是Object类的方法,都只能在同步方法或者同步代码块中使用,否则会抛出异常,另外sleep不会释放锁,wait会释放锁

解决方法一:管程法
  1. //线程安全的arraylist
  2. CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
  3. for (int i = 0; i < 1000; i++) {
  4.     new Thread(()->{
  5.         list.add(Thread.currentThread().getName());
  6.     }).start();
  7. }
  8. Thread.sleep(3000);
  9. System.out.println(list.size());
  10. //1000
复制代码
上面实现的存在一定问题,但是要传达的思想就这样
解决方法二:信号灯法
  1. //当mirror和lipstick都只有一份时
  2.             //获得mirror
  3.             synchronized (mirror){
  4. //                获得了mirror,此时lipstick被另外一个线程占据等待
  5. //                其释放,与此同时占据lipstick的线程也在等待它释放mirror
  6. //                  于是死锁发生了
  7.                 synchronized (lipstick){
  8.                     
  9.                 }
  10.             }
复制代码
线程池

  1. public class MyThread implements  Runnable {
  2.     private static Integer number=10;
  3.     private  boolean flag = true;
  4.     //定义lock锁
  5.     private final  ReentrantLock lock = new ReentrantLock();
  6.     @Override
  7.     public  void run() {
  8.         while (flag) {
  9.             try {
  10.                 Thread.sleep(100);
  11.                 lock.lock();//加锁,上锁区域就是lock到unlock区域
  12.                 if (number < 1) {
  13.                     flag=false;
  14.                 }
  15.                 else {
  16.                     System.out.println(Thread.currentThread().getName() + "--" +number--);
  17.                 }
  18.             } catch (InterruptedException e) {
  19.                 e.printStackTrace();
  20.             } finally {
  21.                 //解锁
  22.                 lock.unlock();
  23.             }
  24.             }
  25.         }
  26.     public static void main(String[] args) {
  27.         MyThread myThread = new MyThread();
  28.         new Thread(myThread,"李").start();
  29.         new Thread(myThread,"马").start();
  30.         new Thread(myThread,"王").start();
  31.     }
  32. }
  33. /*
  34. 马--10
  35. 王--9
  36. 李--8
  37. 李--7
  38. 王--6
  39. 马--5
  40. 王--4
  41. 李--3
  42. 马--2
  43. 马--1
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4