1.线程锁可以嵌套 在多线程编程中,要执行synchronized块: 必须首先获得指定对象的锁 Java的线程锁是可重入的锁.对同一个对象,同一个线程,可以多次获取他的锁,即同一把锁可以嵌套.如以下代码 public void add(int m){ synchronized (lock){ this.value += m; another(m); } } public void addAnother(int m){ synchronized (lock){ this.another += m…
多任务 现代操作系统(windows,MacOS,Linux)都可以执行多任务: 多任务就是同时运行多个任务,例如同时开启钉钉.百度网盘.火狐.谷歌.ps等 操作系统执行多任务就是让多个任务交替执行,例如浏览器执行0.001秒,网盘执行0.001秒,钉钉执行0.001秒.因为任务的数量远远多余CPU的数量,因此任务也是交替执行的 进程.线程 进程(Process):一个任务就是一个进程. 线程(Thread):某些进程内部还需要同时执行多个子任务.例如word打字.拼写检查.打印等 进程和线程的…
wait和notify synchronized解决了多线程竞争的问题 我们可以在synchronized块中安全的对一个变量进行修改,但是它没有解决多线程协调的问题. 例如设计一个TaskQueue,预期效果:线程1通过addTask()不断往队列中添加任务,而线程2可以调用getTask()从队列中获取任务 class TaskQueue{ Queue<String> queue = new LinkedList<>(); public synchronized void ad…
Java语言内置多线程支持: 一个Java程序实际上是一个JVM进程 JVM用一个主线程来执行main()方法 在main()方法中又可以启动多个线程 1.创建新线程 1.1 方法一:使用Thread创建线程 创建MyThread类: 从Thread派生 覆写run()方法 创建MyThread()实例 调用start()启动线程 class MyThread extends Thread{ public void run(){ System.out.println("子线程"); }…
1.中断线程: 如果线程需要执行一个长时间任务,就可能需要中断线程.场景:从网络上下载一个100M的文件,用户在下载过程中中断下载任务的执行. 中断线程就是其他线程给该线程发一个信号,该线程收到信号后结束执行run()方法 1.1中断线程 需要检测isInterrupted()标志,其他线程通过调用interrupt()方法中断该线程 class HelloThread extends Thread{ public void run(){ while(!isInterrupted()){ Sys…
1线程的状态 线程终止的的原因: run()或call()方法执行完成,线程正常结束 线程抛出一个未捕获的Exception或Error 直接调用该线程的stop()方法来结束该线程--该方法容易导致死锁,通常不推荐使用 1.1对已经死亡的线程调用start()方法使他重新启动,会引发IllegalThreadStateException class MyThread extends Thread{ public void run(){ System.out.println("子线程"…
Atomic java.util.concurrent.atomic提供了一组原子类型操作: 如AtomicInteger提供了 int addAndGet(int delta) int incrementAndGet() int get() int compareAndGet() Atomic类可以实现: 无锁(lock-free)实现的线程安全(thread-safe)访问 原理:CAS(Compare and Set)如果AtomicInteger实例的值是prev,就替换为next,返回…
Concurrent 用ReentrantLock+Condition实现Blocking Queue. Blocking Queue:当一个线程调用getTask()时,该方法内部可能让给线程进入等待状态,直到条件满足.线程唤醒以后,getTask()才会返回,而java.util.concurrent提供了线程安全的Blocking集合,如ArrayBlockingQueue. class TaskQueue{ final Queue<String> queue = new LinkedL…
Java语言内置多线程支持: 创建线程需要操作系统资源(线程资源,栈空间) 频繁创建和销毁线程需要消耗大量时间 如果可以复用一个线程 线程池: 线程池维护若干个线程,处于等待状态 如果有新任务,就分配一个空闲线程执行 如果所有线程都处于忙碌状态,新任务放入队列等待 ExecutorService JDK提供了ExecutorService接口表示线程池: ExecutorService executor = Executors.newFixedThreadPool(4); //固定大小的线程池…
ReentrantLock保证单一线程执行 ReentrantLock保证了只有一个线程可以执行临界区代码: 临界区代码:任何时候只有1个线程可以执行的代码块. 临界区指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性.当有线程进入临界区段时,其他线程或是进程必须等待,有一些同步的机制必须在临界区段的进入点与离开点实现,以确保这些共用资源是被互斥获得使用,例如:semaphore.只能被单一线程访问的设备,例如:打印机. public…
多线程是Java实现多任务的基础: Thread ExecutorService ScheduledThreadPool Fork/Join Thread对象代表一个线程:调用Tread.currentThread()获取当前线程. 多任务程序通常需要针对每个任务启动一个新的线程,来处理这个用户的请求,也可以从线程池取出一个空闲的线程来处理. 如何在一个线程内传递状态: 例如我们在一个线程处理过程中,经常需要调用不同的类来处理不同的功能,我们如何在这些方法中能够方便的获取到当前的用户? JDK提…
1.Java使用synchronized对一个方法进行加锁 class Counter{ int count = 0; public synchronized void add(int n){ count += n; } public synchronized void dec(int n){ count -= n; } public int get(){//读取一个int类型是原子操作,不需要同步 return count; } } class AddThread extends Thread…
1.线程安全问题 多个线程同时运行,线程调度由操作系统决定,程序本身无法决定 如果多个线程同时读写共享变量,就可能出现问题 class AddThread extends Thread{ public void run(){ for(int i=0;i<Main.LOOP;i++){ Main.count += 1; } } } class DecThread extends Thread{ public void run(){ for(int i=0;i<Main.LOOP;i++){ Ma…
线程同步: 是因为多线程读写竞争资源需要同步 Java语言提供了synchronized/wait/notify来实现同步 编写多线程同步很困难 所以Java提供了java.util.concurrent包: 更高级的同步功能 简化多线程程序的编写 JDK>= 1.5 java.util.locks.ReentrantLock用于替代synchronized加锁 synchronized是Java语言提供的,不需考虑异常 ReentrantLock是普通的Java类,要用try...finall…
线程池可以高效执行大量小任务: Fork/Join线程池可以执行一种特殊的任务: 把一个大任务拆成多个小任务并行执行 Fork/Join是在JDK 1.7引入的 示例:计算一个大数组的和 Fork/Join就是把一个大人物不断的拆成小任务,执行并行计算的一种模式. class SumTask extends RecursiveTask<Long> { protected Long compute(){ //把一个大任务分拆成2个子任务 SumTask subtask1 = new Sumtas…
使用Future可以获得异步执行结果 Future<String> future = executor.submit(task); String result = future.get(); 但是当我们使用get()获得异步执行结果的时候,这个方法可能会阻塞.我们通过while循环反复调用isDone()来判断异步结果是否已经完成. while(!future.isDone()){ Thread.sleep(1); } String result = future.get() 所以使用Futu…
JDK提供了ExecutorService接口表示线程池,可以通过submit提交一个任务. ExecutorService executor = Executors.newFixedThreadPool(4); executor.submit(task); 但这里的task有个问题,因为继承制Runnable,如果希望返回一个结果,只能用Result来表示,这样主线程获取结果,就很不方便. class Task implements Runnable{ public String result…
Condition实现等待和唤醒线程 java.util.locks.ReentrantLock用于替代synchronized加锁 synchronized可以使用wait和notify实现在条件不满足时的等待,条件满足时的唤醒. class TaskQueue{ final Lock lock = new ReentrantLock() final Condition notEmpty = lock.newCondition(); } 使用Condition对象可以通过await和signa…
TCP多线程编程 一个ServerSocket可以和多个客户端同时建立连接,所以一个Server可以同时与多个客户端建立好的Socket进行双向通信. 因此服务器端,当我们打开一个Socket以后,通常使用一个无限for循环,在这个for循环内部,每次调用accept方法,返回一个与远程客户新建的Socket连接,紧接着启动一个新的线程,来处理这个连接. ServerSocket ss = new ServerSocket(port); for( ; ; ){ Socket sock = ss.…
1.JDK提供的InputStream分为两类: 直接提供数据的InputStream * FileInputStream:从文件读取 * ServletInputStream:从HTTP请求读取数据 * Socket.getInputStream():从TCP连接读取数据 提供额外附加功能的FilterInputStream * 如果要给FileInputStream添加缓冲功能: BufferedFileInputStream extends FileInputStream * 如果要给Fi…
看完上篇博文的介绍后,大家应该大概了解进程和线程的由来.有了这样一个背景我们进一步来看一下线程和进程. 引入进程: 进程能够提高系统的并发性.提高CPU的使用率,从而提高程序的性能.在曾经单道操作系统中,一次仅仅运行一个程序,这样运行效率非常低,资源得不到充分的利用. 所以后来多道操作系统出现了,因为多道操作系统一次并发运行非常多程序,但管理起来非常麻烦. 因此进程的概念就被提出来了,它是一个程序动态运行表现,并且进程中包括了程序的资源,并管理程序怎样去使用资源.能够说进程是程序的一种动态表现形…
1.进程和线程       进程,是一个正在运行的程序实体,windows下常见的就是xxx.exe,在任务管理器中可以看见很多个进程.它是线程的容器. 线程,是进程中的一个执行流.在单线程编程中,我们的程序只有一个执行流:主线程的main方法.流,表明执行的过程是有顺序的,如main函数中的语句需要一条一条的按顺序执行,第一条语句没执行完,就不能去执行第二条语句. 可见,单线程编程是有限制的,那就是我们的语句只能串行执行,不可能发生某些语句同时执行的现象.有时我们希望某些代码并行执行,就好比我…
字符串操作过程中,每次用 + 拼接字符串,有以下问题: 每次循环都会创建新的对象 绝大部分都是临时对象.浪费内存 影响GC效率 String s = ""; for(int i=0;i<1000;i++){ s = s +String.valueOf(i); } System.out.println(s); 为了解决这个问题,Java提供了StringBuilder类,可以高效的拼接字符串 1.StringBuffer类 StringBuilder是可变对象 StringBuil…
1.接口的定义 抽象方法本质上是定义接口规范. 在抽象类中定义了一个抽象方法,子类中必须实现这个抽象方法. public abstract class Person{ public abstract void run(); } public class Student extends Person{ @Override public void run(){} } public class Teacher extends Person{ @Override public void run(){}…
每个子类都可以覆写父类的方法 如果父类的方法没有实际意义,能否去掉方法的执行语句?子类会报编译错误 如果去掉父类的方法,就失去了多态的特性 可以把父类的方法声明为抽象方法. 如果一个class定义了方法,但没有具体执行代码,这个方法就是抽象方法: 抽象方法用abstract修饰 抽象方法没有任何执行语句 因为无法执行抽象方法,因此这个类也必须声明为抽象类abstract class 无法实例化一个抽象类.如果子类不是抽象类,依旧可以被实例化. 抽象类作用: 抽象类用于被继承 抽象类可以强迫子类实…
1.继承 继承是一种代码复用的方式. Student与Person有相同部分的代码. Student可以从Person继承,这样Student获得了Person的所有功能,只需要编写新增的功能即可.通过继承,可以实现代码的复用. 继承使用关键字extends,一个类只能有一个父类. 如果没有写明继承类,编译器会自动指定该类继承于基类Object. Person:超类super,父类,基类 Student:子类subclass,扩展类 Person.java //默认继承Object public…
1.对象的概念 面向对象编程:Object-Oriented Programming 对现实世界建立计算机模型的一种编程方法. 现实世界 计算机模型 Java代码 人 类/class class Person() 小明 实例/ming Person ming = new Person() 小红 示例/hong Person hong = new Persion() 小军 示例/jun Person jun = new Persion() 书 类/class class Book() Java核心…
函数名也是变量: >>> f = abs >>> f(-10) 10 然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数 def add(x, y, f): return f(x) + f(y) x ==> -5 y ==> 6 f ==> abs f(x) + f(y) ==> abs(-5) + abs(6) ==> 11 把函数作为参数传入,这样的函数称为高阶函数,函数式编程就…
1. Socket 在开发网络应用程序的时候,会遇到Socket这个概念. Socket是一个抽象概念,一个应用程序通过一个Socket来建立一个远程连接,而Socket内部通过TCP/IP协议把数据传输到网络. Socket/TCP/部分IP都是由操作系统提供的.不同的编程语言只是提供了对操作系统调用的加单封装,例如Java提供的几个Socket相关的类就封装了操作系统提供的接口. 为什么需要Socket? 因为仅仅通过IP地址进行通信还不够,同一台计算机同一时间会运行多个网络程序.当计算机收…
1. 函数式编程 Java有2类方法: 实例方法:通过实例调用 静态方法:通过类名调用 Java的方法相当于过程式语言的函数 函数式编程(Functional Programing): 把函数作为基本运算单元 函数可以作为变量,传递给另一个函数 函数可以接收函数 函数可以返回函数 历史研究函数式编程的理论是Lambda演算,所以把支持函数式编程的风格成为Lambda表达式 2. Java的单方法接口 在Java中,有许多接口只定义了1个方法: Comparator Runnable Callab…