Java多线程学习

Summary 简单总结

类相关

  1. 域访问权限:

    Current ClassSame PackageChildrenOther Package
    public
    protected
    friendly
    private

    类的访问权限只有publicdefault两种.

  2. 生成对象时加载顺序

    1. 若有父类则从父类开始加载
    2. 静态代码块,静态常量,
    3. 普通代码块,属性,按照代码顺序执行.
    4. 构造器
  3. 对象拷贝

    1. 深浅拷贝两个对象的区别就是浅拷贝不会拷贝对象中的引用对象,而深拷贝则会拷贝一份对象.

          // 浅克隆:
          class ShallowCopy implements Cloneable{
              // 基础类型会拷贝
              private int basic  = 1;
              // 引用类型不会拷贝一份全新的.
              private OtherClass other;
              void setOtherClass(OtherClass other){
                  this.other = other;
              }
              OtherClass getOtherClass(){
                  return this.other;
              }
              // 需要重写Object的clone()方法.
              @Override
              protected Object clone() throws CloneNotSupportedException {
                  return super.clone();
              }
              public String toString() {
              return "ShallowCopy{" +
                      "basic=" + basic +
                      ", OtherClass=" + cloneTest1 +
                      '}';
              }
          }
          main(){
              ShallowCopy shallowCopy = new ShallowCopy();
              shallowCopy.setOtherClass(new OtherClass());
              ShallowCopy copyClass = (ShallowCopy) shallowCopy.clone();
              System.out.println(shallowCopy.toString());
              System.out.println("----");
              System.out.println(copyClass.toString());
          }
      /*    output:
          CloneTest1{basic=1, OtherClass=com.javabase.OtherClass@7cd84586}
          ----
          CloneTest1{basic=1, OtherClass=com.javabase.OtherClass@7cd84586}*/
      
    2. 深拷贝:

      // 深拷贝有两三种方法.
      // 1. 手动克隆.需要手动赋值,且引用对象也要实现Cloneable
      class DeepCopy1 implements Cloneable{
          private OtherClass otherClass;
      
          public OtherClass getOtherClass() {
              return otherClass;
          }
      
          public void setOtherClass(OtherClass otherClass) {
              this.otherClass = otherClass;
          }
      
          @Override
          protected Object clone() throws CloneNotSupportedException {
              DeepCopy1 deepCopy1 = (DeepCopy1) super.clone();
              deepCopy1.setOtherClass((OtherClass) otherClass.clone());
              return deepCopy1;
          }
      }
      // 2. 使用序列化进行克隆.本质就是使用序列化把本对象存储到硬盘,然后再读回来.
      // 也可以使用SerializationUtils的clone(Object obj)方法
      {
      //        将其序列化之后再反序列化,然后再输出.
          OtherClass otherClass = new OtherClass();
          DeepCopy1 deepCopy1 = new DeepCopy1();
          deepCopy1.setOtherClass(otherClass);
       //        尝试序列化
          DeepCopy1 deepCopy2;
          try {
              ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
              ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
              objectOutputStream.writeObject(deepCopy1);
              ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
              deepCopy2 = (DeepCopy1) objectInputStream.readObject();
              System.out.println(deepCopy1);
              System.out.println(deepCopy2);
          } catch (IOException | ClassNotFoundException e) {
              e.printStackTrace();
          }
      
      /*        com.javabase.DeepCopy1@5f4da5c3
          com.javabase.DeepCopy1@4534b60d*/
      
      // 3. 使用JSON工具.来回转换一下.
      

多线程

  1. 三种基本方法.

    1. extends Thread
    2. implements Runnable
    3. implements Callable,这个方法可以返回值.
    class ThreadTest implements Runnable{
    
        @Override
        public void run() {
            println("hello world");
            }
        }
    }
    class ThreadTest implements Callable<String>{
    
        @Override
        public String call() throws Exception {
            return "Hello World";
        }
    }
    main(){
        ExecutorService service = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) {
            // Callable使用submit.Runnable使用execute.
            Future<String> futureTask  = service.submit(new ThreadTest());
            System.out.println(futureTask.get());
        }
    }
    
  2. 处理异常

    1. 由于线程的特殊性线程无法捕捉到抛出到Run外部的异常,所以要么在Run方法内部就把异常处理完,要么就设置一个可以处理这种异常的类

      class testT implements Runnable{
          @Override
          public void run(){
              // 这个线程总是会抛出异常,抛出的异常即使是在try catch块里面也捕捉不到
              throw new RuntimeException;
          }
      }
      
    2. 解决方法一: Thread.currentThread().setUncaughtExceptionHandler(),如果只是单纯的执行new Thread.strat;这种方法是没有问题的,但是如果将线程交给线程池来执行的话,可能会发生仍然捕获不到错误的异常.原因

      public void run() {
          Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
              @Override
              public void uncaughtException(Thread t, Throwable e) {
                  System.out.println(t.getName() + "\t" + e.toString());
              }
          });
      }
      // 写在run方法里有效,写在构造器内无效,猜测还是因为线程池创造的线程会代为执行run方法,所以才会有效.
      
    3. 解决方法二:重写ThreadFactory,这是书本上讲的方法,在初始化线程池的时候创建一个能够为每个线程设置Handler的Factory

      ExecutorService service = Executors.newCachedThreadPool(new ThreadFactory() {
          @Override
          public Thread newThread(Runnable r) {
              Thread t = new Thread(r);
              t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                  @Override
                  public void uncaughtException(Thread t, Throwable e) {
                      System.out.println(t.getName() + "\t" + e.toString());
                  }
              });
          }
      });
      
    4. 1

  3. 同步的方法

    1. synchronized内建字段

    2. 显式的lock方法.

      class LockTest {
          private int value;
      
          tested(int value) {
              this.value = value;
          }
      
          Lock lock = new ReentrantLock();
      
          void setValue() {
              try {
                  locked = lock.tryLock(1000, TimeUnit.MILLISECONDS);
                  this.value += 1;
                  Thread.yield();
                  this.value += 1;
                  System.out.println(this.value);
              } catch (InterruptedException e) {
                  System.out.println(locked);
              } finally {
                  lock.unlock();
              }
          }
      }
      
      

      为什么使用lock

    3. 同步方法块

      1. 同步方法块可以有效减少线程占用方法的时间,效率更高.

      2. synchronized(Object object)方法,一般synchronized(this)即锁定当前对象就是合适的做法,但也可以尝试锁定其他对象.

      3. Lock同步代码块

        void syncBlock1(){
            synchronized(this){
                // do Something
            }
                // do Something
        }
        void syncBlock2(){
            lock.lock();
            try{
               // do something
            }finally{
                lock.unlock();
            }
            // do something
        }
        
    4. ThreadLocal

      class tested {
          ThreadLocal<Integer> local = new ThreadLocal<>() {
              @Override
              protected Integer initialValue() {
                  int a = new Random().nextInt(10);
                  System.out.println(Thread.currentThread().getName() + "\t initial\t" + a);
                  return a;
              }
          };
          void increase(){
              this.local.set(local.get()+1);
              Thread.yield();
              this.local.set(local.get()+1);
              System.out.println(Thread.currentThread().getName()+"\t"+this.local.get());
          }
          void getValue(){
              System.out.println(this.local.get());
          }
      }
      class ThreadTest implements Runnable {
          private tested t;
      
          public ThreadTest(tested t) {
              this.t = t;
          }
      
          @Override
          public void run() {
              t.increase();
      //        t.getValue();
          }
      
      }
      main(){
      ExecutorService service = Executors.newCachedThreadPool();
      tested t= new tested();
      for (int i = 0; i < 5; i++) {
          service.execute(new ThreadTest(t));
      }
      service.shutdown();
      }
      

      在被共享的对象内部使用ThreadLocal类,这样就会为每一个线程都创建一个自己独有的资源.其他线程无法访问. ThreadLocal原理

  4. 线程的中断

    1. Thread.interrupt();

      class ThreadTest implements Runnable {
          @Override
          public void run() {
              System.out.println("test Thread running, ready to sleep");
              try {
                  Thread.sleep(1000);
              } catch (InterruptedException e) {
                  System.out.println("test Thread is interrupted");
                  e.printStackTrace();
              }
          }
      }
      main(){
          Thread t1 = new Thread(new ThreadTest());
          t1.start();
          TimeUnit.MILLISECONDS.sleep(100);
          t1.interrupt();
      }
      /*
      output:
              test Thread running, ready to sleep
              test Thread is interrupted
              java.lang.InterruptedException: sleep interrupted
              at java.base/java.lang.Thread.sleep(Native Method)
              at com.javabase.ThreadTest.run(TestDog.java:53)
              at java.base/java.lang.Thread.run(Thread.java:830)
      */
      
    2. 线程池中断

      // Sleep可以中断,IO和同步,都不可以中断
      //        使用线程池的submit进行中断.
              Future<?> future = service.submit(new ThreadTest(t));
              TimeUnit.MILLISECONDS.sleep(100);
              future.cancel(true);
      
    3. 书中只简单的介绍了两种中断的方法.

  5. 线程的协调工作.

    1. wait,notify,notifyAll都必须放在同步的代码块里面来执行.即线程只有在已经获得锁的情况下来执行对锁的操作.
  6. 1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值