本文关键词:
java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait(),notify(),notifyAll()等方法都定义在Object类中
多线程
•进程:
•正在运行的程序,是系统进行资源分配和调用的独立单位。
•每一个进程都有它自己的内存空间和系统资源。
•线程:
•是进程中的单个顺序控制流,是一条执行路径
•一个进程如果只有一条执行路径,则称为单线程程序。
•一个进程如果有多条执行路径,则称为多线程程序。
多进程的意义?
提高CPU的使用率
多线程的意义?
提高应用程序的使用率
Java程序运行原理
•java命令会启动 java 虚拟机,启动 JVM,等于启动了一个应用程序,也就是启动了一个进程。
该进程会自动启动一个 “主线程” ,然后主线程去调用某个类的 main方法。
所以 main方法运行在主线程中。在此之前的所有程序都是单线程的。
java中对于线程的描述是Thread 其中封装了线程的信息,最重要的还有需要执行的任务的信息
Thread类名的基本获取和设置方法
•public final String getName()
•public final void setName(String name)
•其实通过构造方法也可以给线程起名字
创建线程方式一
继承Thread类
1.子类覆盖父类中的run方法,将线程运行的代码存放在run中。
2.建立子类对象的同时线程也被创建。
3.通过调用start方法开启线程。
创建线程方式二
实现Runnable接口
1.子类覆盖接口中的run方法。
2.通过Thread类创建线程,并将实现了Runnable接口的子类对象作为参数传递给Thread类的构造函数。
3.Thread类对象调用start方法开启线程。
启动一个线程是run()还是start()?它们的区别?
start();
run():封装了被线程执行的代码,直接调用仅仅是普通方法的调用
start():启动线程,并由JVM自动调用run()方法
线程的调度和优先级
线程的调度
分时调度
抢占式调度 (Java采用的是该调度方式)
获取和设置线程优先级
默认是5
范围是1-10
线程的控制方法
•线程休眠
•public static void sleep(long millis)
•线程加入
•public final void join()
•线程礼让
•public static void yield()
•后台线程
•public final void setDaemon(boolean on)
•中断线程
•public final void stop() 过时
•public void interrupt()
停止线程还可以通过定义循环控制标志来解决现成的停止问题
sleep()和wait()方法的区别
sleep():必须指时间;不释放锁。
wait():可以不指定时间,也可以指定时间;释放锁。
为什么wait(),notify(),notifyAll()等方法都定义在Object类中
因为这些方法的调用是依赖于锁对象的,而同步代码块的锁对象是任意锁。
而Object代码任意的对象,所以,定义在这里面。
多线程同时请求共享资源,并且操作的代码不是原子操作的时候
就会出现多线程的安全问题
解决线程安全问题的基本思想
首先想为什么出现问题?(也是我们判断是否有问题的标准)
•是否是多线程环境
•是否有共享数据
•是否有多条语句操作共享数据
如何解决多线程安全问题呢?
•基本思想:让程序没有安全问题的环境。
•怎么实现呢?
•把多个语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可。
同步
同步代码块
•格式:
synchronized(对象){需要同步的代码;}
•同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能。
同步方法
•就是把同步关键字加到方法上
同步方法的锁对象是this
静态同步方法所对象是类名.class 对象
Lock
Lock
•void lock()
•void unlock()
ReentrantLock
线程组
Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
•默认情况下,所有的线程都属于主线程组。
•public final ThreadGroup getThreadGroup()
•我们也可以给线程设置分组
•Thread(ThreadGroup group, Runnable target, String name)
线程池
程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。
而使用线程池可以很好的提高性能
尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。
•线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。
•在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池
JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
•public static ExecutorService newCachedThreadPool()
•public static ExecutorService newFixedThreadPool(int nThreads)
•public static ExecutorService newSingleThreadExecutor()
•这些方法的返回值是ExecutorService对象,
该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法
•Future<?> submit(Runnable task)
•<T> Future<T> submit(Callable<T> task)
实现Callable接口 也可以实现多线程
匿名内部类方式使用多线程
new Thread(){代码…}.start();
New Thread(new Runnable(){代码…}).start();
定时器
定时器是一个应用十分广泛的线程工具,可用于调度多个定时任务以后台线程的方式执行。
在Java中,可以通过Timer和TimerTask类来实现定义调度的功能
Timer
•public Timer()
•public void schedule(TimerTask task, long delay)
•public void schedule(TimerTask task,long delay,long period)
TimerTask
•public abstract void run()
•public boolean cancel()
开发中
Quartz是一个完全由java编写的开源调度框架。
线程类的其他方法
setPriority(int num)
setDaemon(boolean b)
join()
自定义线程名称
toString()