精华内容
下载资源
问答
  • 在单个Java程序中实现多个类的两种方法嵌套类多个非嵌套类编译器如何处理多个非嵌套类在下面的示例中,java程序包含两个类,一个类名为Computer,另一个是Laptop。这两个类都有自己的构造函数和方法。在main方法中,...

    一个Java程序包含两个或多个类,在Java中有两种可能。

    在单个Java程序中实现多个类的两种方法嵌套类

    多个非嵌套类

    编译器如何处理多个非嵌套类

    在下面的示例中,java程序包含两个类,一个类名为Computer,另一个是Laptop。这两个类都有自己的构造函数和方法。在main方法中,我们可以创建两个类的对象并调用它们的方法。

    示例public class Computer {

    Computer() {

    System.out.println("Computer类的构造函数。");

    }

    void computer_method() {

    System.out.println("Power gone! Shut down your PC soon...");

    }

    public static void main(String[] args) {

    Computer c = new Computer();

    Laptop l = new Laptop();

    c.computer_method();

    l.laptop_method();

    }

    }

    class Laptop {

    Laptop() {

    System.out.println("笔记本电脑类的构造函数。");

    }

    void laptop_method() {

    System.out.println("99% Battery available.");

    }

    }

    当我们编译上述程序时,将创建两个.class文件,分别是Computer.class和Laptop.class。这样的好处是我们可以在其他项目中的某个地方重用我们的.class文件,而无需再次编译代码。简而言之,创建的.class文件数将等于代码中的类数。我们可以根据需要创建任意多个类,但是不建议在一个文件中编写多个类,因为这样会使代码难以阅读,而我们可以为每个类创建一个文件。

    输出结果Computer类的构造函数。

    笔记本电脑类的构造函数。

    Power gone! Shut down your PC soon...

    99% Battery available.

    编译器如何处理嵌套类

    编译具有多个内部类的主类后,编译器会为每个内部类生成单独的.class文件。

    示例// Main class

    public class Main {

    class Test1 { // Inner class Test1

    }

    class Test2 { // Inner class Test2

    }

    public static void main(String [] args) {

    new Object() { // Anonymous inner class 1

    };

    new Object() { // Anonymous inner class 2

    };

    System.out.println("Welcome to nhooo.com");

    }

    }

    在上面的程序中,我们有一个Main类,其中有四个内部类Test1,Test2,Anonymous内部类1和Anonymous内部类2。编译完此类后,它将生成以下类文件。

    主类

    Main $Test1.class

    Main $Test2.class

    Main $1.class

    Main $2.class

    输出结果Welcome to nhooo.com

    展开全文
  • 虽然初恋是java, 可是最近是越来越喜欢python, 所以决定追根溯源好好了解下python的原理,架构等等.小脑袋瓜不太好使,只能记录下慢慢进步吧... 首先来一比较容易想到的写法,如下一样嵌套:with open("fi...

    虽然初恋是java, 可是最近是越来越喜欢python, 所以决定追根溯源好好了解下python的原理,架构等等.小脑袋瓜不太好使,只能记录下慢慢进步吧

    使用with打开文件的好处不多说,这里记录一下如果要打开多个文件,该怎么书写简捷的代码。

    场景是同时打开三个文件,文件行数一样,程序实现每个文件依次读取一行,同时输出。 首先来一种比较容易想到的写法,如下一样嵌套:

    with open("file1") as f1:

    with open("file2") as f2:

    with open("file3") as f3:

    for i in f1:

    j = f2.readline()

    k = f3.readline()

    print(i,j,k)

    注意,这里只能对一个文件进行for循环读取,不能写成:

    for i,j,k in f1,f2,f3:

    print(i,j,k)

    这么多层缩进太恶心了,还是来一种简洁些的写法:

    with open("file1") as f1, open("file2") as f2, open("file3") as f3:

    for i in f1:

    j = f2.readline()

    k = f3.readline()

    print(i,j,k)

    还有一种优雅一点的写法:

    from contextlib import nested #这个包是python2中的,不使用python3

    with nested(open("file1"), open("file2"), open("file3")) as (f1,f2,f3):

    for i in f1:

    j = f2.readline()

    k = f3.readline()

    print(i,j,k)

    以上这篇在python中使用with打开多个文件的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

    展开全文
  • java面试宝典

    2013-02-28 16:04:01
    34、是否可以从一个static 方法内部发出对非static 方法的调用? 11 35、写clone()方法时,通常都有一行代码,是什么? 11 36、GC 是什么? 为什么要有GC? 11 37、垃圾回收的优点和原理。并考虑2 回收机制。 11 38...
  • java面试题典 java 面试题 经典

    热门讨论 2010-06-18 13:42:36
    19. java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 21 20. 简述synchronized和java.util.concurrent.locks.Lock的异同 ? 21 21. LINUX下线程,GDI类的解释...
  • main方法是作什么用处的...Java中有几注释,各自的功能 有三: 单行注释//:加在行首只能注释一行 多行注释/* */:注释多行,但不能嵌套使用 文档注释/** */:用于生成HTML形式的文档,需要配合javado
      1. main方法是作什么用处的?

        这是程序的入口方法,是由虚拟机自动调用的。

      2. 语句必须用分号结束吗?

        必须的,但是代码块{}可以用分号结束,也可以不用分号结束

      3. Java中有几种注释,各自的功能

        有三种:

        单行注释//:加在行首只能注释一行

        多行注释/* */:注释多行,但不能嵌套使用

        文档注释/** */:用于生成HTML形式的文档,需要配合javadoc命令实现

      4. Java语言的数据类型是强类型还是弱类型?

        是强类型,意味着每一个变量都必须明确声明数据类型。

      5. Java语言中数据类型的划分?有什么区别?

        分成基本类型和引用类型两大类。

        基本类型:有8种,只能存储单一的值,不以对象的形式存在

        引用类型:除了基本类型之外其他的都是引用类型,能够存储复杂数据类型,以对象的形式存在

      6. 基本类型都有哪8种类型?

        布尔类型:boolean 1字节

        字符类型:char 2字节

        整型:byte 1字节 short 2字节 int 4字节 long 8字节

        浮点型:float 4字节 double 8字节

      7. 布尔值可不可以用0或者非0数代替?

        不可以,布尔值只能是truefalse,不能使用数字,这和C语言是不一样的。

      8. 直接写个整数10默认是什么类型的?

        整型的直接量例如10100等默认的数据类型都是int

      9. 如何让一个整型的直接量变成long型的?

        在直接量后面加大写L后者小写l,例如10L

      10. 直接写一个3.14的直接量是什么数据类型的?

        double型,如果想表示是float3.14必须写成3.14F或者3.14fdouble型的3.14也可以写成3.14D

      11. 常见的转义字符有哪些?

    转义序列

    名称

    \b 

    退格

    \t 

    制表

    \n 

    换行

    \r 

    回车

    \”

    双引号

    \’

    单引号

    \\ 

    反斜杠

     


    展开全文
  • 疯狂JAVA讲义

    2014-10-17 13:35:01
    第1章 Java概述 1 1.1 Java语言的发展简史 2 1.2 Java的竞争对手及各自优势 4 1.2.1 C#简介和优势 4 1.2.2 Ruby简介和优势 4 1.2.3 Python的简介和优势 5 1.3 Java程序运行机制 5 1.3.1 高级语言的运行机制 6...
  • java 面试题 总结

    2009-09-16 08:45:34
    它是基于Java的远程方法调用(RMI)技术的,所以EJB可以被远程访问(跨进程、跨计算机)。但EJB必须被布署在诸如Webspere、WebLogic这样的容器中,EJB客户从不直接访问真正的EJB组件,而是通过其容器访问。EJB容器是...
  • java面试宝典2012

    2012-12-16 20:43:41
    46、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 32 47、sleep() 和 wait() 有什么区别? 33 48、同步和异步有何异同,在什么情况下分别使用他们?举例说明...
  • JAVA面试宝典2010

    2011-12-20 16:13:24
    46、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 29 47、sleep() 和 wait() 有什么区别? 30 48、同步和异步有何异同,在什么情况下分别使用他们?举例说明...
  • Java面试宝典-经典

    2015-03-28 21:44:36
    46、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 29 47、sleep() 和 wait() 有什么区别? 30 48、同步和异步有何异同,在什么情况下分别使用他们?举例说明...
  • JAVA面试题最全集

    2010-03-13 13:09:10
    35.java除了8基本类型外,在虚拟机里还有哪一,有什么作用? 36.除了使用new关键字创建对象意外,试列举另外三以上创建实例的方式? 37.classloader中,JDK的API、Classpath中的同web-inf中的class加载方式有...
  • 由于 JavaScript 不具备如 Java 等语言的严格类模型,因而除非是在处理回调,否则代码中的 this 指向并不清晰。 一般来说,对于部分运行中的代码(非回调)会通过 new 关键字和 Function.prototype ...
  • 最新Java面试宝典pdf版

    热门讨论 2011-08-31 11:29:22
    46、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 29 47、sleep() 和 wait() 有什么区别? 30 48、同步和异步有何异同,在什么情况下分别使用他们?举例说明...
  • Java面试宝典2012版

    2012-12-03 21:57:42
    46、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 29 47、sleep() 和 wait() 有什么区别? 30 48、同步和异步有何异同,在什么情况下分别使用他们?举例...
  • Java面试宝典2012新版

    2012-06-26 19:20:00
    46、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 29 47、sleep() 和 wait() 有什么区别? 30 48、同步和异步有何异同,在什么情况下分别使用他们?举例说明...
  • java面试宝典2012版.pdf

    2012-11-08 19:53:04
    46、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 47、sleep() 和 wait() 有什么区别? 48、同步和异步有何异同,在什么情况下分别使用他们?举例说明。 ...
  • Java面试笔试资料大全

    热门讨论 2011-07-22 14:33:56
    46、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 29 47、sleep() 和 wait() 有什么区别? 30 48、同步和异步有何异同,在什么情况下分别使用他们?举例说明...
  • Java面试宝典2010版

    2011-06-27 09:48:27
    46、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 47、sleep() 和 wait() 有什么区别? 48、同步和异步有何异同,在什么情况下分别使用他们?举例说明。 ...
  • java基础题 很全面

    2009-05-09 09:24:24
    54. java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 13 55. java中有几种类型的流?JDK为每种类型的流提供了一些抽象类以供继承,请说出他们分别是哪些类? 14 56....
  • [Java高并发]进程线程

    2020-05-26 11:47:30
    高并发GO!进程线程进程与线程的区别线程上下文切换比进程上下文切换快线程可以拥有独属于...**解决线程死锁**锁死**线程锁死两情况****信号丢失锁死****嵌套监视器锁死**活锁线程饥饿:JAVA线程实现/创建方式继承 Th

    高并发GO!

    进程线程

    进程与线程的区别

    • 进程是一个“执行中的程序”,是系统进行资源分配和调度的一个独立单位
    • 线程是进程的一个实体,一个进程中一般拥有多个线程
    • 线程之间共享地址空间和其它资源(所以通信和同步等操作,线程比进程更加容易)
    • 线程一般不拥有系统资源,但是也有一些必不可少的资源(使用ThreadLocal存储)
    • 线程上下文的切换比进程上下文切换要快很多。

    线程上下文切换

    • CPU (利用时间片轮转机制)给每个任务都服务一定的时间,然后把当前任务的状态保存下来,在加载下一任务的状态后,继续服务下一任务(时间片轮转的方式使多个任务在同一颗 CPU 上执行变成了可能)
    • 任务的状态保存及再加载, 这段过程就叫做上下文切换
    • 上下文:是指某一时间点 CPU 寄存器和程序计数器的内容
    • 寄存器: 是 CPU 内部的数量较少但是速度很快的内存

    线程上下文切换比进程上下文切换快

    • 进程切换时,涉及到当前进程的CPU环境的保存和新被调度运行进程的CPU环境的设置
    • 线程切换时,仅需要保存和设置少量的寄存器内容,不涉及存储管理方面的操作

    线程可以拥有独属于自己的资源吗?

    可以,通过ThreadLocal可以存储线程的特有对象,也就是属于当前线程的资源

    进程之间常见的通信方式

    • 通过使用套接字Socket来实现不同机器间的进程通信
    • 通过映射一段可以被多个进程访问的共享内存来进行通信
    • 无名管道,有名管道
    • 消息队列
    • 信号

    多线程与单线程的关系

    • 多线程是指在一个进程中,并发执行了多个线程,每个线程都实现了不同的功能在单核CPU中,将CPU分为很小的时间片,在每一时刻只能有一个线程在执行,是一种微观上轮流占用CPU的机制。由于CPU轮询的速度非常快,所以看起来像是“同时”在执行一样

    • 多线程会存在线程上下文切换,会导致程序执行速度变慢

    • 多线程不会提高程序的执行速度,反而会降低速度。但是对于用户来说,可以减少用户的等待响应时间,提高了资源的利用效率

    • 多线程并发利用了CPU轮询时间片的特点,在一个线程进入阻塞状态时,可以快速切换到其余线程执行其余操作

      • 这有利于提高资源的利用率
      • 最大限度的利用系统提供的处理能力
      • 有效减少了用户的等待响应时间
    • 多线程并发编程

      • 数据安全问题
      • 线程之间的竞争也会导致线程死锁和锁死等活性故障
      • 线程之间的上下文切换也会带来额外的开销等问题。

    线程的状态

    • NEW
    • RUNNABLE
    • BLOCKED
    • WAITING
    • TIMED_WAITING
    • TERMINATED

    线程基本方法

    • sleep方法:是Thread类的静态方法,当前线程将睡眠n毫秒,线程进入阻塞状态。当睡眠时间到了,会解除阻塞,进入可运行状态,等待CPU的到来睡眠不释放锁(如果有的话)

    • wait方法:是Object的方法,必须与synchronized关键字一起使用,线程进入阻塞状态,当notify或者notifyall被调用后,会解除阻塞。但是,只有重新获得互斥锁之后才会进入可运行状态。睡眠时,会释放互斥锁

    • join 方法:当前线程调用,当前线程转为阻塞状态,等到另一个线程结束,当前线程再由阻塞状态变为就绪状态,等待 cpu

      -主线程生成并启动了子线程,需要用到子线程返回的结果,也就是需要主线程需要在子线程结束后再结束,这时候就要用到 join() 方法。

    • yield 方法:该方法使得线程让出CPU时间片,与其他线程一起重新竞争 CPU 时间片。不使线程阻塞,线程仍处于可执行状态,随时可能再次分得 CPU 时间

    • interrupt方法: 中断一个线程,是给这个线程一个通知信号,会影响这个线程内部的一个中断标识位。这个线程本身并不会因此而改变状态(如阻塞,终止等)

      • 调用 interrupt()方法并不中断一个正在运行的线程。也就是说处于 Running 状态的线程并不会因为被中断而被终止,只改变了内部维护的中断标识位
      • 若调用 sleep()而使线程处于 TIMED-WATING 状态,这时调用 interrupt()方法,会抛出InterruptedException,从而使线程提前结束 TIMED-WATING 状态
      • 中断状态是线程固有的一个标识位,可以通过此标识位安全的终止线程。比如,你想终止一个线程 thread 的时候,可以调用 thread.interrupt()方法,在线程的 run 方法内部根据thread.isInterrupted()的值来优雅的终止线程
    • notify()

      • 唤醒在此对象监视器上等待的单个线程,如果所有线程都在此对象
        上等待,则会随机选择唤醒其中一个线程
      • 线程通过调用其中一个 wait() 方法,在对象的监视器上等待,直到当前的线程放弃此对象上的锁定,才能继续执行被唤醒的线程,被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争(被唤醒后要重新竞争锁而不是立即执行)
      • notifyAll()唤醒此对象监视器上的所有线程
    • currentThread(): 得到当前线程

    • isDaemon(): 一个线程是否为守护线程

    终止线程 4 种方式

    正常运行结束

    使用退出标志退出线程

    • 有些线程是伺服线程需要长时间的运行,只有在外部某些条件满足的情况下,才能关闭这些线程。使用一个变量来控制循环

    • 例如:最直接的方法就是设一个 boolean 类型的标志,并通过设置这个标志为 true 或 false 来控制 while循环是否退出

        public class ThreadSafe extends Thread
         { public volatile boolean exit = false;
        public void run() { while (!exit){
        //do something }
        }
        }
         定义了一个退出标志 exit,当 exit 为 true 时,while 循环退出,exit 的默认值为 false.在定义 exit 时,使用了一个 Java 关键字 volatile,这个关键字的目的是使 exit 同步,也就是说在同一时刻只能由一个线程来修改 exit 的值
      

    Interrupt 方法结束线程

    线程处于阻塞状态

    • 如使用了 sleep,同步锁的 wait,socket 中的 receiver,accept 等方法时,会使线程处于阻塞状态
    • 当调用线程的 interrupt()方法时,会抛出 InterruptException 异常。
      阻塞中的那个方法抛出这个异常,通过代码捕获该异常,然后 break 跳出循环状态,从而可以结束这个线程的执行
    • 要先捕获 InterruptedException 异常之后通过 break 来跳出循环,才能正常结束 run 方法,而不是一调用interrupt()方法就会结束线程

    线程未处于阻塞状态

    • 使用 isInterrupted()判断线程的中断标志来退出循环

    • 当使用interrupt()方法时,中断标志就会置 true,和使用自定义的标志来控制循环是一样的道理

        public class ThreadSafe extends Thread { public void run()
         {	
         while (!isInterrupted()){ //非阻塞过程中通过判断中断标志来退出 	
         try{
        	Thread.sleep(5*1000);//阻塞过程捕获中断异常来退出 }
        	catch(InterruptedException e){
        	e.printStackTrace();
        	break;//捕获到异常之后,执行 break 跳出循环 }
        	} }
        	}
      

    stop ()

    直接使用 thread.stop()来强行终止线程

    • thread.stop()调用之后,创建子线程的线程就会抛出 ThreadDeatherror 的错误,并且会释放子线程所持有的所有锁
    • 被保护数据因为锁的释放而不一致性,其他线程在使用这些被破坏的数据时,可能导致应用程序错误。并不推荐使用 stop 方法来终止线程

    sleep与wait

    • sleep()方法属于 Thread 类中的,而 wait()方法属于 Object 类
    • sleep()方法导致了程序暂停执行指定的时间,让出 cpu 给其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态
    • 在调用 sleep()方法的过程中,线程不会释放对象锁
    • 而当调用 wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用 notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态(才会被唤醒被尝试加锁 )

    start与run

    • start()方法来启动线程,实现了多线程运行,这时无需等待 run 方法体代码执行完毕,可以直接继续执行下面的代码。
    • 通过调用 Thread 类的 start()方法来启动一个线程, 这时此线程是处于就绪状态, 并没有运行(等待CPU)
    • 方法 run()称为线程体,它包含了要执行的这个线程的内容,线程就进入了运行状态,开始运行 run 函数当中的代码。
    • Run 方法运行结束, 此线程终止,然后 CPU 再调度其它线程。

    线程活性故障

    由于资源的稀缺性或者程序自身的问题导致线程一直处于非Runnable状态,并且其处理任务一直无法完成的现象被称为是线程活性故障。常见的线程活性故障包括死锁,锁死,活锁与线程饥饿。

    线程死锁

    死锁是最常见的一种线程活性故障。死锁的起因是多个线程之间相互等待对方而被永远暂停(处于非Runnable)

    死锁产生四个必要条件

    • 资源互斥:一个资源每次只能被一个线程使用
    • 请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放
    • 不剥夺条件:线程已经获得的资源,在未使用完之前,不能强行剥夺
    • 循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系

    解决线程死锁

    • 粗锁法:使用一个粒度粗的锁来消除“请求与保持条件”,缺点是会明显降低程序的并发性能并且会导致资源的浪费。
    • 锁排序法:(必须回答出来的点)
      指定获取锁的顺序,比如某个线程只有获得A锁和B锁,才能对某资源进行操作
      通过指定锁的获取顺序,比如规定,只有获得A锁的线程才有资格获取B锁,按顺序获取锁就可以避免死锁。这通常被认为是解决死锁很好的一种方法。
    • 使用显式锁中的ReentrantLock.try(long,TimeUnit)来申请锁

    锁死

    线程锁死是指等待线程由于唤醒其所需的条件永远无法成立,或者其他线程无法唤醒这个线程而一直处于非运行状态(线程并未终止)导致其任务 一直无法进展产生死锁的4个必要条件都没有发生,线程锁死仍然可能已经发生

    线程锁死两种情况

    信号丢失锁死

    没有对应的通知线程来将等待线程唤醒,导致等待线程一直处于等待状态

    嵌套监视器锁死

    嵌套监视器锁死是由于嵌套锁导致等待线程永远无法被唤醒的一种故障

    比如一个线程,只释放了内层锁Y.wait(),但是没有释放外层锁X; 但是通知线程必须先获得外层锁X,才可以通过 Y.notifyAll()来唤醒等待线程,这就导致出现了嵌套等待现象。

    活锁

    活锁是一种特殊的线程活性故障。当一个线程一直处于运行状态,但是其所执行的任务却没有任何进展称为活锁比如,一个线程一直在申请其所需要的资源,但是却无法申请成功

    线程饥饿:

    线程饥饿是指线程一直无法获得其所需的资源导致任务一直无法运行的情况。线程调度模式有公平调度和非公平调度两种模式。在线程的非公平调度模式下,就可能出现线程饥饿的情况

    中断

    一个线程执行完毕之后会自动结束,如果在运行过程中发生异常也会提前结束

    InterruptedException

    通过调用一个线程的 interrupt() 来中断该线程,如果该线程处于阻塞、限期等待或者无限期等待状态,那么就会抛出 InterruptedException,从而提前结束该线程;但是不能中断 I/O 阻塞和 synchronized 锁阻塞

    interrupted

    • 如果一个线程的 run() 方法执行一个无限循环,并且没有执行 sleep() 等会抛出 InterruptedException 的操作,那么调用线程的 interrupt() 方法就无法使线程提前结束
    • 但是调用 interrupt() 方法会设置线程的中断标记,此时调用 interrupted() 方法会返回 true。因此可以在循环体中使用 interrupted() 方法来判断线程是否处于中断状态,从而提前结束线程

    Executor 的中断操作

    调用 Executor 的 shutdown() 方法会等待线程都执行完毕之后再关闭,但是如果调用的是 shutdownNow() 方法,则相当于调用每个线程的 interrupt() 方法

    JAVA线程实现/创建方式

    继承 Thread 类

    • 本质上是实现了 Runnable 接口的一个实例,代表一个线程的实例

    • 启动线程的唯一方法就是通过 Thread 类的 start()实例方法

    • start()方法是一个 native 方法,它将启动一个新线
      程,并执行 run()方法

         public class MyThread extends Thread {
         public void run() {
          }
        System.out.println("MyThread.run()");
         }
         MyThread myThread1 = new MyThread();
         myThread1.start();
      

    实现 Runnable 接口

    若类已经 extends 另一个类,无法直接 extends Thread,此时,可以实现一个 Runnable 接口

    		 public class MyThread extends OtherClass implements Runnable {
    	 public void run() {
    	  }
    	System.out.println("MyThread.run()");
    	 }
    
    //启动 MyThread,需要首先实例化一个 Thread,并传入自己的 MyThread 实例:
     MyThread myThread = new MyThread();
     Thread thread = new Thread(myThread);
     thread.start();
     //事实上,当传入一个 Runnable target 参数给 Thread 后,Thread 的 run()方法就会调用
     target.run()
     public void run() {
     if (target != null) {
      }
    target.run();
     }
    

    ExecutorService、Callable、Future 实现有返回值多线程

    • 有返回值的任务必须实现 Callable 接口,无返回值的任务必须 Runnable 接口

    • 执行 Callable 任务后,可以获取一个 Future 的对象,在该对象上调用 get 就可以获取到 Callable 任务 返回的 Object 了,再结合线程池接口 ExecutorService 就可以实现有返回结果的多线程了

        	 //创建一个线程池
         ExecutorService pool = Executors.newFixedThreadPool(taskSize);
         // 创建多个有返回值的任务
          List<Future> list = new
        for
        i = 0; i < taskSize; i++) {
        ArrayList<Future>();
           (int
          Callable c = new
        MyCallable(i + " ");
         // 执行任务并获取 Future 对象
         Future f = pool.submit(c);
         list.add(f);
         }
         // 关闭线程池
         pool.shutdown();
         // 获取所有并发任务的运行结果
          for
        (Future f : list) {
         // 从 Future 对象上获取任务的返回值,并输出到控制台
          System.out.println("res:"
        + f.get().toString());
         }
      

    实现接口 VS 继承 Thread

    实现接口更好

    • Java 不支持多重继承,因此继承了 Thread 类就无法继承其它类,但是可以实现多个接口
    • 类可能只要求可执行就行,继承整个 Thread 类开销过大

    JMM Java内存模型

    • JDK1.2前的Java内存模型总是从主存中读取变量
    • 目前的Java内存模型,线程可以把变量保存本地内存而是在主存中直接读写,这就可能造成数据不一致,此时需要volatile关键之指示JVM该变量不稳定需要去主存读取

    主内存与工作内存

    • 处理器上的寄存器的读写的速度比内存快几个数量级,为了解决这种速度矛盾,在它们之间加入了高速缓存
    • 缓存一致性问题:如果多个缓存共享同一块主内存区域,那么多个缓存的数据可能会不一致
    • 所有的变量都存储在主内存中,每个线程还有自己的工作内存,工作内存存储在高速缓存或者寄存器中,保存了该线程使用的变量的主内存副本拷贝。线程只能直接操作工作内存中的变量,不同线程之间的变量值传递需要通过主内存来完成

    内存模型三大特性

    JMM解决了原子性,可见性,,有序性

    多线程环境下的线程安全

    主要体现在原子性,可见性,有序性

    原子性

    对于涉及到共享变量操作,若该操作从执行线程以外的任意线程来看是不可分割的,那么该操作就是原子操作,具有原子性。

    原子性的实现方式

    • 利用的排他性,保证同一时刻只有一个线程在操作一个共享变量
    • 利用CAS(Compare And Swap)保证
    • Java语言规范中,保证了除long和double型以外的任何变量的写操作都是原子操作
    • Java语言规范中又规定,volatile关键字修饰的变量可以保证其写操作的原子性

    关于原子性

    • 原子性针对的是多个线程的共享变量,所以对于局部变量来说不存在共享问题,也就无所谓是否是原子操作
    • 单线程环境下讨论是否是原子操作没有意义
    • volatile关键字仅仅能保证变量写操作的原子性不保证复合操作,比如说读写操作的原子性

    可见性

    可见性是指一个线程对于共享变量的更新,对于后续访问该变量的线程是否可见的问题

    单处理器中可见性的问题

    单处理器中,由于是多线程并发编程,线程进行上下文切换时会将对变量的更新当作上下文存储起来,导致其余线程无法看到该变量的更新。所以单处理器下的多线程并发编程也会出现可见性问题的

    可见性如何保证

    • 当前处理器需要刷新处理器缓存,使得其余处理器对变量所做的更新可以同步到当前的处理器缓存
    • 当前处理器对共享变量更新之后,需要冲刷处理器缓存,使得该更新可以被写入其余处理器缓存中

    有序性:

    有序性是指一个处理器上运行的线程所执行的内存访问操作在另外一个处理器上运行的线程来看是否有序的问题。

    重排序:

    为了提高程序执行的性能,Java编译器在其认为不影响程序正确性的前提下,可能会对源代码顺序进行一定的调整,导致程序运行顺序与源代码顺序不一致

    重排序是对内存读写操作的一种优化,在单线程环境下不会导致程序的正确性问题,但是多线程环境下可能会影响程序的正确性

    *重排序举例

    Instance instance = new Instance()都发生了啥?
    具体步骤如下所示三步:

    • 在堆内存上分配对象的内存空间
    • 在堆内存上初始化对象
    • 设置instance指向刚分配的内存地址
      第二步和第三步可能会发生重排序,导致引用型变量指向了一个不为null但是也不完整的对象。(在多线程下的单例模式中,我们必须通过volatile来禁止指令重排序

    谈谈你对synchronized关键字的理解。

    synchronized是Java中的一个关键字,是一个内部锁。它可以使用在方法上和方法块上,表示同步方法和同步代码块;也可以用在类上同步一个类(DLC单例)。在多线程环境下,同步方法或者同步代码块在同一时刻只允许有一个线程在执行,其余线程都在等待获取锁,也就是实现了整体并发中的局部串行。

    内部锁底层实现:

    • 进入时,执行monitorenter,将计数器+1,释放锁monitorexit时,计数器-1
    • 当一个线程判断到计数器为0时,则当前锁空闲,可以占用;反之,当前线程进入等待状态

    synchronized内部锁对原子性的保证:

    锁通过互斥来保障原子性,互斥是指一个锁一次只能被一个线程所持有,临界区代码只能被一个线程执行,即保障了原子性。

    synchronized内部锁对可见性的保证:

    synchronized内部锁通过写线程冲刷处理器缓存和读线程刷新处理器缓存保证可见性

    • 获得锁之后,需要刷新处理器缓存,使得前面写线程所做的更新可以同步到本线程
    • 释放锁需要冲刷处理器缓存,使得当前线程对共享数据的改变可以被推送到下一个线程处理器的缓存中

    synchronized内部锁对有序性的保证

    由于原子性和可见性的保证,使得写线程在临界区中所执行的一系列操作在读线程所执行的临界区看起来像是完全按照源代码顺序执行的,即保证了有序性。(原子性和可见性保证了有序性

    JVM对资源的调度

    • 公平调度方式:
      按照申请的先后顺序授予资源的独占权。

    • 非公平调度方式:

    在该策略中,资源的持有线程释放该资源的时候,等待队列中一个线程会被唤醒,而该线程从被唤醒到其继续执行可能需要一段时间。在该段时间内,新来的线程(活跃线程)可以先被授予该资源的独占权。
    如果新来的线程占用该资源的时间不长,那么它完全有可能在被唤醒的线程继续执行前释放相应的资源,从而不影响该被唤醒的线程申请资源。

    公平/非公平调度优缺点分析:

    • 非公平调度策略:

      • 优点:吞吐率较高,单位时间内可以为更多的申请者调配资源
      • 缺点:资源申请者申请资源所需的时间偏差可能较大,并可能出现线程饥饿的现象
    • 公平调度策略:

      • 优点:线程申请资源所需的时间偏差较小;不会出现线程饥饿的现象;适合在资源的持有线程占用资源的时间相对长或者资源的平均申请时间间隔相对长的情况下,或者对资源申请所需的时间偏差有所要求的情况下使用;
      • 缺点:吞吐率较小

    JVM对synchronized内部锁的调度

    • JVM对内部锁的调度是一种非公平的调度方式,JVM会给每个内部锁分配一个入口集(Entry Set),用于记录等待获得相应内部锁的线程
    • 当锁被持有的线程释放的时候,该锁的入口集中的任意一个线程将会被唤醒,从而得到再次申请锁的机会。被唤醒的线程等待占用处理器运行时可能还有其他新的活跃线程与该线程抢占这个被释放的锁

    synchronized使用方式

    • 修饰实例方法,给当前对象实例枷锁,进入同步代码块前需要获得当前对象的实例
    • 修饰静态方法,是对当前类对象进行加锁,进入同步代码块前需要获得当前类对象的锁(给当前类对象加锁会作用于当前类对象所有实例)
    • 修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码块前需要获得给定对象的锁

    谈谈你对volatile关键字的理解

    volatile关键字是一个轻量级的锁,可以保证可见性和有序性,但是不保证原子性

    volatile对可见性的保证

    volatile 可以保证主内存和工作内存直接产生交互,进行读写操作,保证可见性

    volatile对有序性的保证

    volatile可以禁止指令重排序(通过插入内存屏障),典型案例是在单例模式中使用

    volatile不保证原子性

    volatile 仅能保证变量写操作的原子性,不能保证读写操作的原子性

    volatile变量的开销:

    volatile不会导致线程上下文切换,但是其读取变量的成本较高,因为其每次都需要从高速缓存或者主内存中读取,无法直接从寄存器中读取变量

    volatile在什么情况下可以替代锁?

    • volatile是一个轻量级的锁,适合多个线程共享一个状态变量锁适合多个线程共享一组状态变量
    • 可以将多个线程共享的一组状态变量合并成一个对象,用一个volatile变量来引用该对象,从而替代锁

    new instance指令重排

    Instance instance = new instance三步

    • 在堆上分配instance内存空间
    • 在堆上进行初始化
    • 将引用指向对象实例

    为了保证执行效率JIT编译器会将2,3进行重排序,可能会导致返回一个不为NULl但是也不完整的对象,所以需要用volatile进行防止指令重排

    synchronized与volatile区别

    • volatile是线程同步的轻量级实现,只用于变量;synchronied用于方法和代码块(且在java1.6后进行了优化引入了偏向锁轻量级锁减少获得锁解锁的开销)
    • 多线程访问volatile不会阻塞;synchronized可能会发生阻塞
    • volatile不保证原子性而保障可见性和有序性;synchronized均保证
    • volatile主要用于解决多线程间共享变量的可见性,synchronized主要用于解决多线程间资源同步性

    synchronized和ReenTrantLock 的区别

    • 两者都是可重入锁即自己可以再次获取自己的内部锁
    • synchronized 依赖于 JVM 而 ReenTrantLock 依赖于 API
      synchronized 依赖于 JVM 实现,所以JDK1.6后做了大量JVM层面优化,ReenTrantLock是通过JDK层面实现的
    • ReenTrantLock 比 synchronized 增加了一些高级功能 ,
      • 提供能够中断等待锁的线程机制
      • 可以指定是公平锁还是非公平锁,synchronized只能是非公平锁
      • 可以锁绑定多个条件(一个ReentrantLock同时绑定多个Condition对象)

    ThreadLocal

    ThreadLocalMap

    • 最终变量是存放在当前线程的ThreadLocalMap中,ThreadLocal是对ThreadLocalMap的封装(ThreadLocalMap其实是ThreadLocal的静态内部类)
    • ThreadLocalMap的键值对,Key为ThreadLocal对象,value为ThreadLocal对象调用Set 方法设置的值
    • 每个线程只有一个ThreadLocalMap。例如在一个线程中声明多个ThreadLocal对象使用的是相同的ThreadLocalMap存放数据

    ThreadLocal内存泄漏问题

    • ThreadLocalMap中key为ThreadLocal的弱引用,value为强饮用,所以GC时key会被清理掉而value不会,所以出现key为空的Entry,value永远得不到清理会导致内存泄漏
    • ThreadLocalMap优化,在set() get() remove()会清除掉key为null的记录,使用完 ThreadLocal方法后最好手动调用remove()方法

    线程间协作

    当多个线程可以一起工作去解决某个问题时,如果某些部分必须在其它部分之前完成,那么就需要对线程进行协调

    • join():在线程中调用另一个线程的 join() 方法,会将当前线程挂起,而不是忙等待,直到目标线程结束
    • wait() notify() notifyAll()
    • await() signal() signalAll():java.util.concurrent 类库中提供了 Condition 类来实现线程之间的协调,可以在 Condition 上调用 await() 方法使线程等待,其它线程调用 signal() 或 signalAll() 方法唤醒等待的线程;相比于 wait() 这种等待方式,await() 可以指定等待的条件,因此更加灵活

    JUC组件汇总

    • JUC.Condition类
    • JUC.lock
    • JUC.Atomic
    • FutureTask
    • BlockingQueue
    • AQS(JUC核心组件)

    线程不安全示例

    如果多个线程对同一个共享数据进行访问而不采取同步操作的话,那么操作的结果是不一致的

    以下代码演示了 1000 个线程同时对 cnt 执行自增操作,操作结束之后它的值有可能小于 1000

    public class ThreadUnsafeExample {
    
        private int cnt = 0;
    
        public void add() {
            cnt++;
        }
    
        public int get() {
            return cnt;
        }
    }
    public static void main(String[] args) throws InterruptedException {
    final int threadSize = 1000;
    ThreadUnsafeExample example = new ThreadUnsafeExample();
    final CountDownLatch countDownLatch = new CountDownLatch(threadSize);
    ExecutorService executorService = Executors.newCachedThreadPool();
    for (int i = 0; i < threadSize; i++) {
        executorService.execute(() -> {
            example.add();
            countDownLatch.countDown();
        });
    }
    countDownLatch.await();
    executorService.shutdown();
    System.out.println(example.get());
    

    }

    线程安全

    多个线程不管以何种方式访问某个类,并且在主调代码中不需要进行同步,都能表现正确的行为,实现方式有:

    不可变

    • 不可变(Immutable)的对象一定是线程安全的,不需要再采取任何的线程安全保障措施

    • 不可变的类型:

      • final 关键字修饰的基本数据类型
      • String
      • 枚举类型
      • Number 部分子类,如 Long 和 Double 等数值包装类型,BigInteger 和 BigDecimal 等大数据类型。但同为 Number 的原子类 AtomicInteger 和 AtomicLong 则是可变的

    互斥同步(阻塞同步)

    • synchronized 和 ReentrantLock
    • 互斥同步最主要的问题就是线程阻塞和唤醒所带来的性能问题

    非阻塞同步

    乐观

    AtomicInteger

    CAS机制

    ABA问题

    锁优化

    JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:无锁状态(unlocked)、偏向锁状态(biasble)、轻量级锁状态(lightweight locked)和重量级锁状态(inflated)

    • 偏向锁:偏向锁的思想是偏向于让第一个获取锁对象的线程,这个线程在之后获取该锁就不再需要进行同步操作,甚至连 CAS 操作也不再需要
    • 轻量级锁是相对于传统的重量级锁而言,它使用 CAS 操作来避免重量级锁使用互斥量的开销。对于绝大部分的锁,在整个同步周期内都是不存在竞争的,因此也就不需要都使用互斥量进行同步,可以先采用 CAS 操作进行同步,如果 CAS 失败了再改用互斥量进行同步
    展开全文
  • Java 面试宝典

    2013-02-01 10:02:08
    4、在 JAVA 中如何跳出当前的多重嵌套循环? .......................................................... 8 5、switch 语句能否作用在 byte 上,能否作用在 long 上,能否作用在 String 上? .. 9 6、short s1 = ...
  • 46、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 29 47、sleep() 和 wait() 有什么区别? 30 48、同步和异步有何异同,在什么情况下分别使用他们?举例说明...
  • java范例开发大全

    2013-03-08 20:06:54
    实例48 try…catch嵌套捕获异常的实例 68 4.4 throws声明异常 69 实例49 throws声明异常实例一 69 实例50 throws声明异常实例二 70 4.5 throw抛出异常 72 实例51 throw抛出异常实例一 72 实例52 throw抛出异常实例二...
  • 46、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 29 47、sleep() 和 wait() 有什么区别? 30 48、同步和异步有何异同,在什么情况下分别使用他们?举例说明...
  • 它是基于Java的远程方法调用(RMI)技术的,所以EJB可以被远程访问(跨进程、跨计算机)。但EJB必须被布署在诸如Webspere、WebLogic这样的容器中,EJB客户从不直接访问真正的EJB组件,而是通过其容器访问。EJB容器是...
  • java范例开发大全源代码

    热门讨论 2011-10-30 23:31:51
     实例48 try…catch嵌套捕获异常的实例 68  4.4 throws声明异常 69  实例49 throws声明异常实例一 69  实例50 throws声明异常实例二 70  4.5 throw抛出异常 72  实例51 throw抛出异常实例一 72  ...
  • Java范例开发大全 (源程序)

    热门讨论 2011-04-27 07:47:22
     实例48 try…catch嵌套捕获异常的实例 68  4.4 throws声明异常 69  实例49 throws声明异常实例一 69  实例50 throws声明异常实例二 70  4.5 throw抛出异常 72  实例51 throw抛出异常实例一 72  实例52...
  • java范例开发大全(pdf&源码)

    热门讨论 2013-07-04 13:04:40
    实例48 try…catch嵌套捕获异常的实例 68 4.4 throws声明异常 69 实例49 throws声明异常实例一 69 实例50 throws声明异常实例二 70 4.5 throw抛出异常 72 实例51 throw抛出异常实例一 72 实例52 throw抛出异常实例二...

空空如也

空空如也

1 2 3 4
收藏数 61
精华内容 24
关键字:

java种方法可以嵌套吗

java 订阅