------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
一,进程和线程的概念:
要了解"线程",必须先了解一下"进程":
什么是进程:
1.对于"操作系统"而言,每个独立运行的程序就是独立的"进程";
2."操作系统"会分别针对每个"进程"分配一块独立的内存空间;
--什么是多进程:
1."操作系统"可以同时维护多个"应用程序"的执行。
2.每个应用程序都交由操作系统管理,在某个时间点上,会有一个应用程序被操作系统分配给CPU去执行,执行一会后,会被操作系统
终止执行,并交由另一个"应用程序"继续执行。由于转换非常快,CPU的运算速度也非常快,这就让我们感觉好像是多个应用程序在
同时执行一样。
3.多进程的意义:
1).方便了我们用户的使用。我们可以同时启动多个程序,一边听歌,一边上网,一边下载;
2).充分的利用CPU资源;
什么是线程:
1.线程是由一个"进程"的内部启动的,可以脱离于"主进程"而独立运行的一块代码;
2.一个线程一旦启动,将和"主进程"并行运行,一起面对操作系统,抢占系统资源;
3.一个"进程"可以启动多个"线程";
-- 什么是多线程:
1.一个进程可以同时启动多个线程去单独运行;这个程序就是一个多线程程序;
2.多线程的意义:
1).可以使我们的应用程序"同时"运行多个非常复杂的代码;
2).使我们的程序不用等待那些代码的执行完毕,就可以继续获得执行;
3).充分的利用了CPU的资源;
什么是"并行"和"并发":
1."并行"是指逻辑上一起在执行,它强调的是在"同一段时间内"一起运行的程序;
2."并发"是指物理上的抢占同一资源。它强调的是在"同一时刻时"一起抢占系统的某个共享资源;
二, 实现线程的:
方式一
实现步骤:
1.自定义一个线程类,要继承自Thread;
2.重写Thread中的run()方法;将要在线程中执行的代码写到这里;
3.启动线程:
1).实例化一个我们自定义的线程类;
2).调用它的start()方法;启动线程;
注意:
1.一个线程类,可以实例化多个对象,并分别启动。也就意味着多个线程同时运行;
2.一个线程对象,只能调用一次start,不能重复调用。否则抛出异常:java.lang.IllegalThreadStateException
1.即使我们不去设定线程名称,每个线程都会有一个默认的线程名称;
2.获取线程名:
String getName();
默认的线程名称:Thread - "索引值(按启动顺序,从0开始)"
3.设置线程名称:
void setName(String name):
Java的线程的优先级范围:1--10(从低到高)
设置优先级:setPriority(int n):n一定要在1--10之间,否则抛异常;
获取优先级:getPriority():
注意:
1.Java中的优先级跟操作系统的优先级往往不匹配,不要依赖于优先级,去试图让某些线程先执行完毕,因为这得不到保证;
2.如果线程的内部工作非常简单,那么设置优先级的效果将不会明显;
线程的休眠sleep()方法:
public static void sleep(long millis)
1.使用Thread类名就可以调用;
2.参数:睡眠的时间,单位毫秒;
线程的礼让:
public static void yield()
1.直接使用类名就可以调用;
2.调用的线程,会退回到就绪的状态,同其它线程站在同一起跑线上,等待着被操作系统分配资源;
礼让的线程,很有可能被再次分配到执行权;
守护线程:
1).我们可以将我们的线程设为:守护线程;(开出的线程守护着主进程,主进程结束,线程就跟着结束)
2).如果主进程结束,那么守护线程也会结束。但不会立即结束,会有个小缓冲;
3).设置方式:
public final void setDaemon(boolean on):on为true,则设定为守护线程
终止线程:
public final void stop()
public void interrupt():只有当线程处于以下三种状态的阻塞时,才会有效:
1.Object-->wait()
2.Thread-->sleep();
3.Thread-->join();
当调用interrupt()方法时,会促使虚拟机产生一个InterruptedException异常
并且被线程内的上述三个方法调用的catch捕获,捕获到后,可以结束线程的执行;
实现线程的方式二:
1.自定义类实现:Runnable接口;
2.重写接口中的run()方法;
3.启动线程:
1).实例化自定义类对象;
2).实例化一个Thread对象,将我们的自定义对象作为参数传给Thread的构造器;
3).调用Thread的start()方法启动线程;
1.自定义线程类,实现Callable接口;
2.重写里面的call()方法;
3.启动线程:
1).获取一个线程池;
2).调用线程池submit()方法执行;
1.将可能被多个线程同时并发访问的代码使用关键字:synchronized加锁;
2.使用格式:
synchronized(被锁的对象){
//可能被并发访问的代码
}
说明:
被锁的对象:是一个对象的引用,表示"被锁的对象",意味着,如果一个线程正在访问这个"被锁对象"的synchronized
代码块时,其它线程不能访问这个对象中的任何的synchronized的代码块或synchronized的方法;
同步的特点好处和弊端:
1.特点:当一个代码块被同步后,当一个线程访问时,其它线程列队等待。它能保证同一时刻只为一个线程服务,一个线程执行完毕,才能轮到下一个线程执行;
2.好处:可以解决多线程访问的并发性问题;
3.弊端:因为要使其它线程列队等待,所以会有其它额外的操作,而且这些操作都非常耗时,所以效率比较低;
三,线程组:
1.可以将一些线程进行"分组管理";
2.可以对"一组的线程"进行统一管理;
可以增加管理效率;
3.Java中用ThreadGroup类表示线程组;
Thread类的getThreadGroup():获取当前线程所在的线程组;
默认情况下,所有的线程都属于"主线程组"
ThreadGroup:
构造方法:
ThreadGroup(String name) :构造一个新线程组。
将线程添加到某个线程组。使用Thread的构造方法;
Thread(ThreadGroup group, Runnable target, String name)
我们可以对一个组内的所有线程统一操作:
四,线程池的作用:
1).它可以将一些线程对象缓存起来;
2).当再次需要这些线程时,直接从线程池中取出,并执行即可。不需要重新构造;
3).这样的话,对于一些"构造很复杂"的线程用起来就非常的方便;
JDK5提供的线程池:
1).Executors类:内部提供了一些静态方法,可以获取线程池对象
public static ExecutorService newCachedThreadPool():创建一个可根据需要创建新线程的线程池,
public static ExecutorService newFixedThreadPool(int nThreads):创建一个可重用固定线程数的线程池,
public static ExecutorService newSingleThreadExecutor():创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程
2).调用submit()方法执行并缓存一个线程:
Future<?> submit(Runnable task)
五,JDK5的实现线程的方式,可以返回值了。
1.执行线程:
1).获取一个线程池;
2).调用线程池的submit()方法可以执行线程,并获取返回值:
Future<?> submit(Runnable task)
3).从Future内部获取值:
V get()
六,匿名内部类的形式实现线程:
1.new Thread(){匿名内部类};
2.new Thread(Runnable的匿名内部类){};
3.new Thread(Runnable的匿名内部类){匿名内部类};
简单工厂模式:
1.我们之前获取某个类的对象,都是直接使用类名,直接new一个对象;
Cat c = new Cat();
Dog d = new Dog();
2.简单工厂方法:不需要前端直接面对和使用某个具体类,在前端和具体类中间提供一个"工厂类",由"工厂类"提供方法来获取对象
方式一:
工厂内部,直接提供获取某个对象的方法
1.定义产品的接口:此例:IAnimal
2.定义工厂的接口:此例:IFactory
3.当我们添加一个新的产品时:
1).定义产品类,实现"产品的接口"
2).定义工厂类,实现"工厂的接口"
4.在main()中,直接实例化一个具体的工厂对象,获取具体产品;
优点:每当新增一个新的产品时,无需对原有的任何工厂类及其他类进行修改;
缺点:类太多
八, 单例模式:饿汉式
单例:例:实例;
在整个程序运行期间,全局对于某个类,只能产生一个这个类的对象。可以把这个类设计成"单例模式";
1.防止外部任意的实例化此类对象,将构造方法私有化
2.内部定义一个此类型的成员变量;并初始化;声明为:private static
3.为了封装性,将成员属性私有,提供公有方法获取这个对象;声明为:public static
单例模式:懒汉式
1.将构造方法私有化;
2.提供私有成员,但不初始化;
3.提供公有方法,先判断成员变量是否为null,如果为null,进行实例化。否则直接返回引用;
注意:由于方法内操作步骤较多,另外有可能被多线程并发访问,所以加:synchronized关键字;
九,Runtime类:每个 Java 应用程序都有"一个"Runtime 类实例
1.此类没有构造方法;
2.通过内部的一个静态方法getRuntime()获取此类实例
3.此类就是"单例模式",饿汉式
一,进程和线程的概念:
要了解"线程",必须先了解一下"进程":
什么是进程:
1.对于"操作系统"而言,每个独立运行的程序就是独立的"进程";
2."操作系统"会分别针对每个"进程"分配一块独立的内存空间;
--什么是多进程:
1."操作系统"可以同时维护多个"应用程序"的执行。
2.每个应用程序都交由操作系统管理,在某个时间点上,会有一个应用程序被操作系统分配给CPU去执行,执行一会后,会被操作系统
终止执行,并交由另一个"应用程序"继续执行。由于转换非常快,CPU的运算速度也非常快,这就让我们感觉好像是多个应用程序在
同时执行一样。
3.多进程的意义:
1).方便了我们用户的使用。我们可以同时启动多个程序,一边听歌,一边上网,一边下载;
2).充分的利用CPU资源;
什么是线程:
1.线程是由一个"进程"的内部启动的,可以脱离于"主进程"而独立运行的一块代码;
2.一个线程一旦启动,将和"主进程"并行运行,一起面对操作系统,抢占系统资源;
3.一个"进程"可以启动多个"线程";
-- 什么是多线程:
1.一个进程可以同时启动多个线程去单独运行;这个程序就是一个多线程程序;
2.多线程的意义:
1).可以使我们的应用程序"同时"运行多个非常复杂的代码;
2).使我们的程序不用等待那些代码的执行完毕,就可以继续获得执行;
3).充分的利用了CPU的资源;
什么是"并行"和"并发":
1."并行"是指逻辑上一起在执行,它强调的是在"同一段时间内"一起运行的程序;
2."并发"是指物理上的抢占同一资源。它强调的是在"同一时刻时"一起抢占系统的某个共享资源;
二, 实现线程的:
方式一
实现步骤:
1.自定义一个线程类,要继承自Thread;
2.重写Thread中的run()方法;将要在线程中执行的代码写到这里;
3.启动线程:
1).实例化一个我们自定义的线程类;
2).调用它的start()方法;启动线程;
注意:
1.一个线程类,可以实例化多个对象,并分别启动。也就意味着多个线程同时运行;
2.一个线程对象,只能调用一次start,不能重复调用。否则抛出异常:java.lang.IllegalThreadStateException
3.只用调用start()才是启动线程。run()方法内的代码会以一个线程的方式去运行;
public class Demo {
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
// t1.run();//相当于普通的方法调用,不是启动一个线程
// t2.run();//相当于普通的方法调用,不是启动一个线程
t1.start();
t2.start();
for(int i = 0;i < 100;i++){
System.out.println("主进程 i = " + i);
}
//尝试再次启动t1
// t1.start();//运行时异常。不能多次调用start(),否则抛出异常:java.lang.IllegalThreadStateException
}
}
设置和获取线程的名称:
1.即使我们不去设定线程名称,每个线程都会有一个默认的线程名称;
2.获取线程名:
String getName();
默认的线程名称:Thread - "索引值(按启动顺序,从0开始)"
3.设置线程名称:
void setName(String name):
Java的线程的优先级范围:1--10(从低到高)
设置优先级:setPriority(int n):n一定要在1--10之间,否则抛异常;
获取优先级:getPriority():
注意:
1.Java中的优先级跟操作系统的优先级往往不匹配,不要依赖于优先级,去试图让某些线程先执行完毕,因为这得不到保证;
2.如果线程的内部工作非常简单,那么设置优先级的效果将不会明显;
线程的休眠sleep()方法:
public static void sleep(long millis)
1.使用Thread类名就可以调用;
2.参数:睡眠的时间,单位毫秒;
线程的礼让:
public static void yield()
1.直接使用类名就可以调用;
2.调用的线程,会退回到就绪的状态,同其它线程站在同一起跑线上,等待着被操作系统分配资源;
礼让的线程,很有可能被再次分配到执行权;
守护线程:
1).我们可以将我们的线程设为:守护线程;(开出的线程守护着主进程,主进程结束,线程就跟着结束)
2).如果主进程结束,那么守护线程也会结束。但不会立即结束,会有个小缓冲;
3).设置方式:
public final void setDaemon(boolean on):on为true,则设定为守护线程
终止线程:
public final void stop()
public void interrupt():只有当线程处于以下三种状态的阻塞时,才会有效:
1.Object-->wait()
2.Thread-->sleep();
3.Thread-->join();
当调用interrupt()方法时,会促使虚拟机产生一个InterruptedException异常
并且被线程内的上述三个方法调用的catch捕获,捕获到后,可以结束线程的执行;
实现线程的方式二:
1.自定义类实现:Runnable接口;
2.重写接口中的run()方法;
3.启动线程:
1).实例化自定义类对象;
2).实例化一个Thread对象,将我们的自定义对象作为参数传给Thread的构造器;
3).调用Thread的start()方法启动线程;
public class Demo {
public static void main(String[] args) {
//1).实例化自定义类对象;
MyRunnable run = new MyRunnable();
//2).实例化一个Thread对象,将我们的自定义对象作为参数传给Thread的构造器;
Thread t = new Thread(run);
//3).调用Thread的start()方法启动线程;
t.start();
//写成一句话
new Thread(new MyRunnable()).start();
}
}
实现线程的方式3:1.自定义线程类,实现Callable接口;
2.重写里面的call()方法;
3.启动线程:
1).获取一个线程池;
2).调用线程池submit()方法执行;
public class Demo {
public static void main(String[] args) {
//1.获取一个线程池
ExecutorService service = Executors.newFixedThreadPool(2);
//2.调用submit()方法启动线程
service.submit(new MyCallable());
//关闭线程池
service.shutdown();
解决并发性访问的问题:
1.将可能被多个线程同时并发访问的代码使用关键字:synchronized加锁;
2.使用格式:
synchronized(被锁的对象){
//可能被并发访问的代码
}
说明:
被锁的对象:是一个对象的引用,表示"被锁的对象",意味着,如果一个线程正在访问这个"被锁对象"的synchronized
代码块时,其它线程不能访问这个对象中的任何的synchronized的代码块或synchronized的方法;
同步的特点好处和弊端:
1.特点:当一个代码块被同步后,当一个线程访问时,其它线程列队等待。它能保证同一时刻只为一个线程服务,一个线程执行完毕,才能轮到下一个线程执行;
2.好处:可以解决多线程访问的并发性问题;
3.弊端:因为要使其它线程列队等待,所以会有其它额外的操作,而且这些操作都非常耗时,所以效率比较低;
三,线程组:
1.可以将一些线程进行"分组管理";
2.可以对"一组的线程"进行统一管理;
可以增加管理效率;
3.Java中用ThreadGroup类表示线程组;
Thread类的getThreadGroup():获取当前线程所在的线程组;
默认情况下,所有的线程都属于"主线程组"
ThreadGroup:
构造方法:
ThreadGroup(String name) :构造一个新线程组。
将线程添加到某个线程组。使用Thread的构造方法;
Thread(ThreadGroup group, Runnable target, String name)
我们可以对一个组内的所有线程统一操作:
四,线程池的作用:
1).它可以将一些线程对象缓存起来;
2).当再次需要这些线程时,直接从线程池中取出,并执行即可。不需要重新构造;
3).这样的话,对于一些"构造很复杂"的线程用起来就非常的方便;
JDK5提供的线程池:
1).Executors类:内部提供了一些静态方法,可以获取线程池对象
public static ExecutorService newCachedThreadPool():创建一个可根据需要创建新线程的线程池,
public static ExecutorService newFixedThreadPool(int nThreads):创建一个可重用固定线程数的线程池,
public static ExecutorService newSingleThreadExecutor():创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程
2).调用submit()方法执行并缓存一个线程:
Future<?> submit(Runnable task)
五,JDK5的实现线程的方式,可以返回值了。
1.执行线程:
1).获取一个线程池;
2).调用线程池的submit()方法可以执行线程,并获取返回值:
Future<?> submit(Runnable task)
3).从Future内部获取值:
V get()
六,匿名内部类的形式实现线程:
1.new Thread(){匿名内部类};
2.new Thread(Runnable的匿名内部类){};
3.new Thread(Runnable的匿名内部类){匿名内部类};
public class Demo {
public static void main(String[] args) {
//1.new Thread(){};
new Thread(){
//直接重写run()方法
public void run(){
System.out.println("a");
}
}.start();
//2.new Thread(Runnable的匿名内部类){};
new Thread(new Runnable(){
@Override
public void run() {
System.out.println("b");
}
}){}.start();
//3.new Thread(Runnable的匿名内部类){匿名内部类};
new Thread(new Runnable(){
public void run(){
System.out.println("c");
}
}){
public void run(){
System.out.println("d");
}
}.start();
}
}
七,设计模式
简单工厂模式:
1.我们之前获取某个类的对象,都是直接使用类名,直接new一个对象;
Cat c = new Cat();
Dog d = new Dog();
2.简单工厂方法:不需要前端直接面对和使用某个具体类,在前端和具体类中间提供一个"工厂类",由"工厂类"提供方法来获取对象
方式一:
工厂内部,直接提供获取某个对象的方法
class AnimalFactory{
public Cat getCat(){
return new Cat();
}
public Dog getDog(){
return new Dog();
}
}
方式二:
工厂内部,提供一个获取动物的方法,然后通过形参来判断需要获取的是哪个动物
class Animal{}
class Cat extends Animal{};
class Dog extends Animal{};
class Pig extends Animal{};
class AnimalFactory{
public Animal getAnimal(String type){
if(type.equals("猫")){
return new Cat();
}else if(type.equals("狗")){
return new Dog();
}
}
}
工厂方法模式:
1.定义产品的接口:此例:IAnimal
2.定义工厂的接口:此例:IFactory
3.当我们添加一个新的产品时:
1).定义产品类,实现"产品的接口"
2).定义工厂类,实现"工厂的接口"
4.在main()中,直接实例化一个具体的工厂对象,获取具体产品;
优点:每当新增一个新的产品时,无需对原有的任何工厂类及其他类进行修改;
缺点:类太多
八, 单例模式:饿汉式
单例:例:实例;
在整个程序运行期间,全局对于某个类,只能产生一个这个类的对象。可以把这个类设计成"单例模式";
1.防止外部任意的实例化此类对象,将构造方法私有化
2.内部定义一个此类型的成员变量;并初始化;声明为:private static
3.为了封装性,将成员属性私有,提供公有方法获取这个对象;声明为:public static
单例模式:懒汉式
1.将构造方法私有化;
2.提供私有成员,但不初始化;
3.提供公有方法,先判断成员变量是否为null,如果为null,进行实例化。否则直接返回引用;
注意:由于方法内操作步骤较多,另外有可能被多线程并发访问,所以加:synchronized关键字;
九,Runtime类:每个 Java 应用程序都有"一个"Runtime 类实例
1.此类没有构造方法;
2.通过内部的一个静态方法getRuntime()获取此类实例
3.此类就是"单例模式",饿汉式