黑马程序员---多线程

                                 ------<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

  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.此类就是"单例模式",饿汉式





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值