前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java之多线程

java之多线程

作者头像
暴躁的程序猿
发布2022-03-24 15:43:53
2660
发布2022-03-24 15:43:53
举报
文章被收录于专栏:阿飞的学习记录

线程

是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。

每个线程都有一个优先级,高优先级线程的执行优先于低优先级线程。每个线程都可以或不可以标记为一个守护程序。当某个线程中运行的代码创建一个新 Thread 对象时,该新线程的初始优先级被设定为创建线程的优先级,并且当且仅当创建线程是守护线程时,新线程才是守护程序。

多线程执行时,到底在内存中是如何运行的呢? 多线程执行时,在栈内存中,其实每一个执行线程都有一片自己所属的栈内存空间。进行方法的压栈和弹栈。当执行线程的任务结束了,线程自动在栈内存中释放了。但是当所有的执行线程都结束了,那么进程就结束了。

创建多线程的方法

创建新执行线程有两种方法。 一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例。 例: 打印的方法

代码语言:javascript
复制
/**
     * 第一种方法继承thread
     */
    class MyThread extends Thread{
        private int tid;
        public MyThread(int tid){
                 this.tid=tid;
           }
         //启动需要重载run方法
        @Override
        public void run() {
            try{
                for (int i=0;i<10;i++) {
                     Thread.sleep(1000);//每个一秒打印一个
                    System.out.println(String.format("T%d:%d",tid,i));//打印0-10
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }


//调用
  public static void testThread(){
      for(int i=0;i<10;i++){
           new MyThread(i).start();//循环开启十条线程
    }

创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后可以分配该类的实例,在创建 Thread 时作为一个参数来传递并启动。

代码语言:javascript
复制
public static void testThread(){{
  //第二种方法   实现runnable匿名内部类
        for(int  i = 0;i < 10; ++i){
            final int tid=1;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try{
                        for (int i=0;i<10;i++) {
//                    Random random = new Random();
                            Thread.sleep(1000);//每个一秒打印一个
                            System.out.println(String.format("T%d:%d",tid,i));//打印0-10
                        }
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }).start();
    }
}

  public static void main(String[] args) {
             testThread();
  }

Thread和Runnable的区别

如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。 总结: 实现Runnable接口比继承Thread类所具有的优势:

适合多个相同的程序代码的线程去共享同一个资源 可以避免java中的单继承的局限性。 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。

线程安全

如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。 引发的问题 例如卖票 可能两个人买到了同一张票 那么怎么解决这个问题呢 要解决上述多线程并发访问一个资源的安全性问题:也就是解决重复票与不存在票问题,Java中提供了同步机制(synchronized)来解决。

synchronized

代码语言:javascript
复制
   private static Object obj=new Object();
    //锁
     public static void testSynchronized1(){
         //被锁锁住之后只能等这个对象执行完之后才能执行下一个
        synchronized (obj){
            try{
                for (int i=0;i<10;i++) {
//                    Random random = new Random();
                    Thread.sleep(1000);//每个一秒打印一个
                    System.out.println(String.format("T3%d",i));//打印0-10
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
     }
   //锁
    public static void testSynchronized2(){
        synchronized (obj){
            try{
                for (int i=0;i<10;i++) {
//                    Random random = new Random();
                    Thread.sleep(1000);//每个一秒打印一个
                    System.out.println(String.format("T4%d",i));//打印0-10
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
         public static void testSynchronized(){
         for (int i=0;i<10;i++){
             new Thread(new Runnable() {
                 @Override
                 public void run() {
                     testSynchronized1();
                     testSynchronized2();
                 }
             }).start();
         }
     }
在这里插入图片描述
在这里插入图片描述

只有当一个锁运行完毕之后第二个才会运行 不会出现抢占。

BlockingQueue

BlockingQueue即阻塞队列 阻塞队列主要用在生产者/消费者的场景 负责生产的线程不断的制造新对象并插入到阻塞队列中,直到达到这个队列的上限值。队列达到上限值之后生产线程将会被阻塞,直到消费的线程对这个队列进行消费。 例:生产者与消费者 生产者

代码语言:javascript
复制
  static class Producer implements Runnable{
       private BlockingQueue<String> q;
    //创建一个发事件的队列
       public Producer(BlockingQueue<String> q){
           this.q=q;
       }
        @Override
        public void run() {
         try{
             for(int i=0;i<10;i++){
                 //向消息队列里面放数据   每隔一秒放一个
                 Thread.sleep(1000);
                 q.put(String.valueOf(i));
             }
         }catch(Exception e){
             e.printStackTrace();
         }
        }
    }

消费者

代码语言:javascript
复制
 /**
     * 一个消费者   那面放消息  这面消费消息
     */
    static class Consumer implements Runnable{
        private BlockingQueue<String> q;
        //创建一个发事件的队列        阻塞队列
        public Consumer(BlockingQueue<String> q){
            this.q=q;
        }

        @Override
        public void run() {

          try {
              while(true){
                  //获取当前线程 名字   把队列里面的东西取出来   如果没有就一直卡着
                  System.out.println(Thread.currentThread().getName()+q.take());
              }
          }catch (Exception e){
              e.printStackTrace();
          }

        }
    }

开启线程

代码语言:javascript
复制
   /**
     * 两件事情  一个线程能插入数据
     * 两个线程能取数据
     */
    public static void testBlockQueue(){
          //初始化一个BlockingQueue指定它的容量大小为10
           BlockingQueue<String> q=new ArrayBlockingQueue<String>(10);
           //开启一条放东西的线程
           new Thread(new Producer(q)).start();
           //开启两条消费的线程
           new Thread(new Consumer(q),"Consumer1").start();
           new Thread(new Consumer(q),"Consumer2").start();
    }
代码语言:javascript
复制
  public static void main(String[] args) {
        testBlockQueue();
  }

生产者放进10个产品之后 消费者两个进程取出

在这里插入图片描述
在这里插入图片描述

负责消费的线程不断的从队列中消费对象,直到这个队列为空,当队列为空时,消费线程将会被阻塞,除非队列中有新的对象被插入。

AtomicInteger

用原子方式更新的 int 值 java中的运算操作,自增或自减,若没有进行额外的同步操作,在多线程环境下就是线程不安全的。 多线程并发共享这个变量时会出现问题 AtomicInteger原子操作则不会出现问题 演示 定义了一个普通的变量和AtomicInteger 原子操作类 定义了一个随机睡眠的方法

代码语言:javascript
复制
private static int counter=0;
private static AtomicInteger atomicInteger=new AtomicInteger(0);
//定义一个睡眠的方法
public static void sleep(int mills){
    try{
        Thread.sleep(new Random().nextInt(mills));//随机睡眠的方法
    }catch (Exception e){
        e.printStackTrace();
    }
}

原子操作增加

代码语言:javascript
复制
 /**
     * 对一个变量读写的操作
     * AtomicIntegerAtomicInteger
     * 一个提供原子操作的Integer的类。
     * 在Java语言中,++i和i++操作并不是线程安全的,
     * 在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。
     * public final int get() //获取当前的值
     * public final int getAndSet(int newValue)//获取当前的值,并设置新的值
     * public final int getAndIncrement()//获取当前的值,并自增
     * public final int getAndDecrement() //获取当前的值,并自减
     * public final int getAndAdd(int delta) //获取当前的值,并加上预期的值
     */
    public  static void testWithAtomic(){
        for (int i=0;i<10;++i){
            new Thread(new Runnable() {
                @Override
                public void run() {
                   sleep(1000);//随机在一秒以内的时间睡眠
                    for (int j=0;j<10;++j){
                        System.out.println(atomicInteger.incrementAndGet());//incrementAndGet()以原子方式将当前值加 1。
                    }
                }
            }).start();
        }
    }

普通自增

代码语言:javascript
复制
    /**
     *利用多线程的变量加减
     */
  public static void testWithoutAtomic(){
      for (int i=0;i<10;++i){
          new Thread(new Runnable() {
              @Override
              public void run() {
                  sleep(1000);//随机在一秒以内的时间睡眠
                  for (int j=0;j<10;++j){
                      counter++;//java里的运算(比如自增)并不是原子性的。
                      System.out.println(counter);
                  }
              }
          }).start();
      }
  }

测试

代码语言:javascript
复制
  public static void testAtomic(){
 //测试原子的
     testWithAtomic();
//      testWithoutAtomic();
  }

每次都能输出到100 而自增会出现达不到100的状况

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/04/08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 线程
  • 创建多线程的方法
  • Thread和Runnable的区别
  • 线程安全
  • synchronized
  • BlockingQueue
  • AtomicInteger
相关产品与服务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档