精华内容
下载资源
问答
  • 基本概念 ...线程就是进程内部程序流,是轻量级,新建线程会共享所在进程的资源,因此对系统的资源消耗比较小,以后开发中采用多线程技术是主流方式。 目前主流操作系统都是采用时间片轮...

    基本概念

    程序 - 主要指存放在硬盘/磁盘上的可执行文件。
    进程 - 主要指运行在内存中的程序。

    目前主流的操作系统都支持多进程,为了同时执行多个任务,进程是重量级的,新建进程对系统的资源消耗比较大,因此进程的数量还是有限的。
    线程就是指进程内部的程序流,是轻量级的,新建线程会共享所在进程的资源,因此对系统的资源消耗比较小,以后开发中采用多线程技术是主流的方式。
    目前主流的操作系统都是采用时间片轮转法来保证多个任务的并发执行效果,所谓的并发就是指宏观并行微观串行。
    

    线程的创建(重中之重)

    (1)使用Thread类创建线程
    java.lang.Thread类用于描述线程,Java虚拟机允许应用程序并发地运行多个执行线程

    创建并启动线程的方式有两种:

    a.自定义类继承Thread类并重写run()方法,然后创建对象调用start()方法。
    b.自定义类实现Runnable接口并重写run方法,创建Thread类对象,参数传递Runnable接口的引用,再调run方法。
    

    继承Thread类的方法:

    public class TestThreadStart extends Thread{
    	@Override
    	public void run(){
    		System.out.println("调用run方法");
    	}
    	public static void main(String[] args) {	
    		TestThreadStart tts = new TestThreadStart();		//使用子类的引用指向子类的对象
    		tts.start();								//调用start()方法,自动调用run()方法
    		System.out.println("调用start方法");
    	}
    }
    

    实现Runnable接口的方法:

    当使用Runnable引用作为参数构造对象时(尽量理解):
    
    a.new Runnable接口的实现类对象传递给Thread类的构造方法。
    b.Thread类的构造方法将实现类对象传递给init()方法。
    c.init方法的内部将实现类对象传递给成员变量target。
    d.在run()方法中判断成员变量target是否为空,若不为空则调用run()方法。
    由于target引用指向实现类的对象,因此在运行阶段调用实现类中的run()方法。
    
    
    public class TestRunnableRun implements Runnable{
    	@Override
    	public void run(){
    		System.out.println("你到底会不会调用我呢?");
    	}
    	public static void main(String[] args) {
    		//声明一个Thread类的引用记录本类的对象,参数传递Runnable接口的引用
    		Thread t1 = new Thread(new TestRunnableRun());
    		//调用run()方法,最终调用上述类中的run()方法
    		t1.run();		
    		System.out.println("程序正常结束了!");
    	}
    }
    

    匿名内部类的方法:

    public class TestNoNameStart {
    	public static void main(String[] args) {
    		//采用继承Thread类的方式加上匿名内部类来创建并启动一个线程
    		Thread t1 = new Thread(){
    			@Override
    			public void run(){
    				System.out.println("继承Thread+匿名内部类");
    			}
    		};
    		t1.start();
    		
    		//采用实现接口的方式加上匿名内部类来创建并启动一个线程
    		Runnable r = new Runnable(){
    			@Override
    			public void run(){
    				System.out.println("实现接口+匿名内部类");
    			}
    		};
    		Thread t2 = new Thread(r);
    		t2.start();
    	}
    }
    

    备注:

    a.继承的方式代码相对简单,但Java语言支持单继承,若继承Thread类则无法继承其他父类.
    b.实现接口的方式代码相对复杂,但不影响该类继承其他父类,并且支持多实现,
      从项目的可维护性上来说,推荐使用该方式。
    

    (2)Thread类的方法

    Thread() - 使用无参的方式构造对象。
    Thread(Runnable target) - 根据参数指定的接口引用来构造对象。实参可传实现类的对象,或使用匿名内部类。
    Thread(String name) - 根据参数指定的名称来构造对象。
    Thread(Runnable target, String name) - 参数指定接口引用和名称。
    
    void run() - 若使用Runnable接口作为参数构造的线程对象,则最终调用接口中的run()方法;			
    			否则该方法啥也不做直接返回。 
    void start() - 启动线程并自动调用run()方法。
    

    (3)原理分析
    执行main()方法的线程叫做主线程,执行run()方法的线程叫做新线程/子线程。
    对于start()方法之前的代码来说,只会被主线程执行一次,当start()方法调用成功后,线程的个数瞬间由1个变成了2个,其中新创建出来的线程去执行run()方法,原来执行main()方法的主线程继续向下执行,两个线程各自独立运行。
    当run()方法结束时,则子线程结束;当main()方法结束时,则主线程结束。
    主线程和子线程之间没有明确的执行先后次序,由系统的调度算法来决定。

    线程的名称和编号(熟悉)

    String getName() - 用于获取线程的名称。
    void setName(String name) - 用于设置线程的名称为参数指定的数值。
    long getId() - 用于获取线程的编号。
    static Thread currentThread() - 用于返回当前正在执行的线程对象的引用。
    

    线程的主要状态(熟悉)

    新建状态 - 当使用new关键字创建完线程对象之后的状态。此时线程并没有开始执行。
    就绪状态 - 调用start()方法之后进入的状态。此时线程依然没有开始执行。
    运行状态 - 当线程调度器调度该线程之后进入的状态。此时线程【正式开始】执行。
    		  若时间片执行结束但任务没有做完就回到就绪状态。
    消亡状态 - 当时间片执行结束并且任务已经完成时进入的状态。此时【线程终止】。
    阻塞状态 - 当线程执行的过程中发生了阻塞事件进入的状态,如:sleep()方法。
               当阻塞状态解除后进入就绪状态而不是运行状态。
    

    线程类的常用方法

    static void yield() - 用于让出当前线程执行权,也就是暂停执行当前线程,转而执行其他线程(了解)。
    static void sleep(long millis) - 用于让当前线程休眠参数指定的毫秒数。
    static void sleep(long millis, int nanos)  -用于让当前线程休眠指定毫秒+纳秒
    		1秒=1000毫秒  1毫秒=1000微秒  1微秒 = 1000纳秒
    void interrupt() - 中断线程,通常用于打断线程的休眠操作(了解)。
    void setPriority(int newPriority) - 用于更改线程的优先级为参数指定的数值。
    int getPriority() - 用于获取线程的优先级并返回。
    
    【优先级高的线程并不一定先执行,只是获取到时间片的机会更多一些】
    
    void join() - 用于主线程等待该线程终止。
    void join(long millis) - 等待该线程终止的时间最长为参数指定的毫秒。
    void join(long millis, int nanos) - 等待该线程终止的最长时间为参数指定的毫秒 + 参数指定的纳秒。
    
    void setDaemon(boolean on) - 用于将该线程设置为守护线程/用户线程。
       - 守护线程用于守护其他线程,当其他线程都结束时,守护线程随之结束。
    

    要求重点掌握的方法:sleep()方法 和 join()方法。

    代码实现

    Join等待线程终止

    public class TestThreadJoin extends Thread {
    	@Override
    	public void run(){
    		//让子线程模拟倒计时的效果
    		for(int i = 20; i > 0; i--){
    			System.out.println("倒计时开始,还有" + i + "秒!");
    			try {
    				Thread.sleep(1000);		//让当前线程休眠
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    	}
    	public static void main(String[] args) {
    		TestThreadJoin ttj = new TestThreadJoin();
    		ttj.start();
    		//让主线程等待子线程的执行,等子线程结束后主线程再结束
    		System.out.println("主线程开始等待...");
    		try {
    			//ttj.join(); //谁调用join()方法主线程就等待谁结束
    			ttj.join(3000); //主线程等待ttj执行3秒钟,之后就不等待了
    		} catch (InterruptedException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		//System.out.println("终于等到你还好没放弃,主线程结束!");
    		System.out.println("实在等不起,GoodBye!");
    	}
    }
    主线程开始等待...
    倒计时开始,还有20秒!
    倒计时开始,还有19秒!
    倒计时开始,还有18秒!
    实在等不起,GoodBye!
    倒计时开始,还有17秒!...
    

    Priority线程优先级

    public class TestThreadPriority extends Thread {
    	@Override
    	public void run(){
    		for(int i = 0;i<20;i++){
    			System.out.println("子线程:i = "+i);
    		}
    	}
    	public static void main(String[] args) {
    		TestThreadPriority ttp = new TestThreadPriority();
    		System.out.println("子线程初始优先级为:"+ttp.getPriority());
    		ttp.setPriority(MAX_PRIORITY);
    		System.out.println("子线程修改后的优先级为:"+ttp.getPriority());
    		ttp.start();
    		
    		//返回当前正在执行的线程对象的引用。
    		Thread main = Thread.currentThread();
    		System.out.println("主线程初始优先级为:"+main.getPriority());
    		main.setPriority(MIN_PRIORITY);
    		System.out.println("主线程修改后的优先级为:"+main.getPriority());
    		for(int j = 0;j<20;j++){
    			System.out.println("---主线程:"+j);
    		}	
    	}
    }
    

    Daemon守护线程

    public class TestThreadDaemon extends Thread{
    	@Override
    	public void run(){
    		for(int i = 0; i < 50; i++){
    			System.out.println("子线程中:i = " + i);
    				try {
    					Thread.sleep(1000);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    		}
    	}
    	public static void main(String[] args) {
    		TestThreadDaemon ttd = new TestThreadDaemon();
    		ttd.setDaemon(true);	//将子线程设置为守护线程
    		ttd.start();
    		try {
    			Thread.sleep(3000);	//主线程等待5秒后开始执行
    		} catch (InterruptedException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		System.out.println("主程序结束");	//输出后主线程执行完成,子线程也随之结束
    	}
    }
    
    子线程中:i = 0
    子线程中:i = 1
    子线程中:i = 2
    主程序结束
    

    线程的同步机制(重点)

    StringBuffer类属于线程安全的类,支持线程的同步机制,执行效率低。
    StringBuilder类属于非线程安全的类,不支持线程的同步机制,执行效率高。

    当多个线程同时访问同一种共享资源时可能会造成数据的不一致性,此时就需要进行线程之间的协调,而线程之间的协调和通信就叫做线程的同步机制。即一个方法使用这个关键字后,当有多个对象调用该方法时,先调用的占用该方法,只有该对象调用完成后,下一对象才可调用该方法。

    解决方案
    由程序案例可知:当多个线程同时访问账户余额时,会导致最终账户余额不正确。
    导致的原因:其中一个线程还没有完成操作时,第二个线程就开始访问账户余额。
    解决方案:将多个线程之间并行的操作改为串行的操作。
    经验:上述方案会导致程序的执行效率变低,因此能不用则不用。

    实现方式
    在Java语言中使用synchronized关键字来实现同步锁机制,从而保证操作的原子性。
    a.使用同步语句块来实现同步锁机制,语法格式如下:
    synchronized(锁对象的引用){ //常用this
    编写所有需要锁定的语句块;
    }
    b.使用synchronized关键字修饰方法,表示锁定整个方法的所有方法体。等价于:
    synchronized(this){
    编写所有需要锁定的语句块;
    }

    死锁的发生

    线程一执行的代码:
    public void run(){
        synchronized(a){      持有对象锁a,等待对象锁b
            synchronized(b){
                ... ...
            }
        }
    }            
    线程二执行的代码:
    public void run(){
    	synchronized(b){      持有对象锁b,等待对象锁a
    		synchronized(a){
    			... ...
    		}
    	}
    }            
    以后的开发中不要进行同步语句块的嵌套使用。
    

    Object类的常用方法

    void wait() - 用于让当前线程进入等待状态,直到其他线程调用notify()/notifyAll()方法 
    void wait(long timeout) - 用于让当前线程进入等待状态,直到调用上述方法或者参数指定的毫秒到了。
    void wait(long timeout, int nanos)- 用于让当前线程进入等待状态,直到参数指定的毫秒+纳秒到了或调用方法
    void notify() - 用于唤醒等待的单个线程(随机)。
    void notifyAll() - 用于唤醒等待的所有线程。
    
    展开全文
  • 操作系统是以进程为单位分配系统资源(主要CPU资源) 如果进程有多个线程, 这些线程共享该进程的资源 每个线程都有独立栈空间, 共享堆区与方法区 主线程 JVM启动主线程,主线程执行main方法 用户线程 程序员...

    进程
    在操作系统中运行的程序
    线程
    线程是进程的一个 执行单元, 一条执行路径
    如: 360安全卫士就是一个进程, 其中电脑体检/木马查杀/电脑清理等就是该进程的执行单元
    多线程:
    一个进程至少有一个线程
    如果进程有多个执行路径,它就是多线程应用程序
    注意:
    操作系统是以进程为单位分配系统资源(主要是指CPU资源)
    如果进程有多个线程, 这些线程共享该进程的资源
    每个线程都有独立的栈空间, 共享堆区与方法区
    在这里插入图片描述

    主线程
    JVM启动的主线程,主线程执行main方法
    用户线程
    程序员开启的新的线程,也称子线程
    守护线程
    为其他线程提供服务的线程. 如垃圾回收器
    当JVM中只有守护线程时, JVM就退出, 守护线程不能单独执行

    2.2创建线程的方式
    Thread类

    2.2.1 定义类继承Thread
    class SubThread extends Thread{
    public void run(){
    子线程要执行的代码
    }
    }
    Subthread t1 = new SubThread();
    t1.start();

    package com.bjpowernode.demo02;
    /**
     * 创建线程的方式一
     * 		定义Thread类的子类
     * @author Administrator
     *
     */
    public class Test01 {
    
    	public static void main(String[] args) {
    		// 3)创建线程对象
    		SubThread t1 = new SubThread();
    		//4) 开启新的线程
    		t1.start(); 		//调用start()会开启新的线程, 新的线程会执行run()
    //		t1.run(); 	//仅仅是普通的实例方法的调用, 不会开启新的线程
    		
    		//main线程
    		for( int i = 1; i <= 100 ; i++){
    			System.out.println( "main==>" + i);
    		}
    		/*
    		 * 运行程序, t1线程和main线程在同时执行, 每次执行的结果可能不一样
    		 * 	当前main线程和t1线程, 谁抢到CPU执行权谁就执行
    		 * 	在单核CPU中,某一时刻CPU只能执行一个任务 , CPU执行速度非常快, 可以快速的在各个线程之间切换
    		 * 	对于用户来说,好像是多个线程在同时执行
    		 * 
    		 */
    	}
    
    }
    
    //1)定义类继承Thread
    class SubThread extends Thread{
    	//2)重写run()
    	@Override
    	public void run() {
    		// run()方法中的代码就是子线程要执行的代码
    		for( int i = 1; i <= 100 ; i++){
    			System.out.println( "sub thread-->" + i);
    		}
    	}
    }
    
    

    2.2.2 定义Runnable接口的实现类
    class Prime1 implements Runnable{
    public void run(){
    子线程执行的代码
    }
    }
    Thread t2 = new Thread( new Prime1() );
    t2.start();

    package com.bjpowernode.demo02;
    /**
     * 创建线程的方式二
     * 	定义Runnable接口的实现类
     * @author Administrator
     *
     */
    public class Test02 {
    
    	public static void main(String[] args) {
    		//3) 创建线程对象
    		Prime target = new Prime();
    		//Thread构造方法的形参是一个Runnable接口,调用方法时,传递接口的实现类对象
    		Thread t2 = new Thread(target);
    		//4) 开启新的线程
    		t2.start();
    		
    		//main线程
    		for( int i = 1; i <= 100 ; i++){
    			System.out.println( "main==>" + i);
    		}
    	}
    
    }
    
    //1)定义类实现Runnable接口
    class Prime implements Runnable{
    	//2)重写Runnable接口的run()
    	@Override
    	public void run() {
    		// 就是子线程 要执行的代码
    		for( int i = 1; i <= 100 ; i++){
    			System.out.println( "sub thread-->" + i);
    		}
    	}
    	
    }
    

    还可以这样:

    package com.bjpowernode.demo02;
    /**
     * Runnable接口的匿名内部类对象
     * @author Administrator
     *
     */
    public class Test03 {
    
    	public static void main(String[] args) {
    		Thread t3 = new Thread(new Runnable() {
    			//在匿名内部类中重写抽象方法 
    			@Override
    			public void run() {
    				for( int i = 1; i <= 100 ; i++){
    					System.out.println( "sub thread-->" + i);
    				}
    			}
    		});
    		
    		t3.start();
    		
    		//main线程
    		for( int i = 1; i <= 100 ; i++){
    			System.out.println( "main==>" + i);
    		}
    		
    	}
    
    }
    
    

    2.2.3 定义Callable接口的实现类
    class Prime2 implements Calllable {
    public Integer call() throws Exception{
    子线程执行的代码
    return xxx;
    }
    }

    Prime2  p = new Prime2();
    FutureTask<Integer>  task = new FutureTask<>(  p  );
    Thread  t3 = new Thread( task); 
    t3.start();
    //在主线程中获得子线程的返回值
    Integer  i1  = task.get();
    
    package com.bjpowernode.demo02;
    
    import java.util.Random;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    
    /**
     * 创建线程的方式三
     * 		Callable接口
     * 		Callable接口中的call()方法有返回值, Runnable接口的run()方法没有返回值
     * Callable接口经常用于线程池中创建线程
     * 
     * @author Administrator
     *
     */
    public class Test04 {
    
    	public static void main(String[] args) throws InterruptedException, ExecutionException {
    		//3)线程线程对象
    		Prime22 p = new Prime22(); 		//创建Callable接口的实现类对象
    		//FutureTask构造方法是Callable接口, 调用时传递Callable接口的实现类对象
    		FutureTask<Integer> task = new FutureTask<>(p);
    		//FutureTask类实现了RunnableFuture, RunnableFuture接口继承了Runnable接口
    		//FutureTask类就是Runnable接口的实现类
    		Thread t4 = new Thread(task);
    		// 4) 开启线程
    		t4.start();
    
    		// main线程
    		for (int i = 1; i <= 100; i++) {
    			System.out.println("main==>" + i);
    		}
    		
    		//获得子线程的返回值
    		Integer i1 = task.get();
    		System.out.println( "i1==" + i1);
    	}
    
    }
    
    //1) 定义类实现Callable接口, Callable接口的泛型指定call()方法的返回值类型
    class  Prime22  implements Callable<Integer>{
    	//2) 重写call()方法, 该方法体就是子线程要执行的代码
    	@Override
    	public Integer call() throws Exception {
    		int num = new Random().nextInt(100);
    		System.out.println(" call :: num==" + num );
    		return num;
    	}
    	
    }
    

    2.3 线程的常用方法
    static int activeCount() 返回活动线程的数量.
    static Thread currentThread() 返回当前线程
    ClassLoader getContextClassLoader() 返回线程上下文类加载器.
    long getId() 返回线程的ID,每个线程都有唯一的Id.
    String getName() 返回线程的名称
    int getPriority() 线程优先级
    Thread.State getState() 返回线程的状态.
    void interrupt() 中断线程.
    static boolean interrupted() 判断线程的中断标志.
    boolean isAlive() 判断线程是否结束 .
    boolean isDaemon() 判断是否为守护线程
    boolean isInterrupted() 判断线程是否被中断.
    void join() 线程加入,线程合并
    void join(long millis)
    void run() 线程要执行的代码
    void setDaemon(boolean on) 设置线程为守护线程.
    void setName(String name)设置线程名称.
    void setPriority(int newPriority) 设置优先级
    static void sleep(long millis) 线程休眠.
    void start() 开启新的线程
    void stop() 终止线程的执行
    String toString().
    static void yield() 线程让步

    package com.bjpowernode.demo02;
    /*
     * Thread.currentThread()		返回当前线程
     * getName()					线程名称, 默认名称 Thread-0
     * t2.setName("t2");			设置线程名称
     * Thread.activeCount()			活动线程的数量
     * t1.isAlive()					判断线程是否结束 
     * 
     */
    public class Test05 {
    
    	public static void main(String[] args) {
    		System.out.println( "111:" + Thread.activeCount() ); 		//1
    		
    		SubThread t1 = new SubThread();
    		t1.start();
    		System.out.println( "222:" + Thread.activeCount() ); 		//2
    		
    		Thread t2 = new Thread( new Prime() );
    		t2.setName("t2");
    		t2.start();
    		System.out.println("333:  t1 is alive: " + t1.isAlive() );   //true
    		System.out.println( "333:" + Thread.activeCount() ); 		//3
    		
    		//main线程
    		for(int i = 1; i<=100; i++){
    			System.out.println( Thread.currentThread().getName() + "--------------->" + i );
    		}
    		
    		System.out.println("444:  t1 is alive: " + t1.isAlive() );   //true
    		System.out.println("444:  t2 is alive: " + t2.isAlive() );   //true
    		System.out.println( "4444:" + Thread.activeCount() ); 		//3
    		
    		
    	}
    	
    	//1)静态内部类, 继承Thread
    	static class SubThread extends Thread{
    		@Override
    		public void run() {
    			for( int  i  = 1; i <= 100; i++){
    //				System.out.println("sub thread-->" + i);
    				System.out.println( Thread.currentThread().getName() + "==>" + i );
    			}
    		}
    	}
    	
    	//2)
    	static class Prime implements Runnable{
    		@Override
    		public void run() {
    			for( int  i  = 1; i <= 100; i++){
    				System.out.println( Thread.currentThread().getName() + "==>" + i );
    			}
    		}
    	}
    
    }
    
    
    package com.bjpowernode.demo02;
    /**
     * 守护线程
     * 		当JVM中只有守护线程时, JVM退出
     * t1.setDaemon(true);  	设置为守护线程
     * @author Administrator
     *
     */
    public class Test06 {
    
    	public static void main(String[] args) {
    		//创建线程
    		Thread t1 = new Thread(new Runnable() {
    			@Override
    			public void run() {
    				for(int i = 1; i <= 500; i++){
    					System.out.println( Thread.currentThread().getName() + "==>" + i);
    				}
    			}
    		});
    		t1.setDaemon(true); 			//把t1设置为守护线程
    		t1.start();
    		
    		//main线程
    		for(int i = 1; i <= 100; i++){
    			System.out.println( Thread.currentThread().getName() + "-->" + i);
    		}
    		
    	}
    
    }
    
    
    展开全文
  • 单例模式(Singleton Pattern)是一种常用的软件设计模式,是一个类的实例从始至终只能被创建一次,同时它提供一个静态的getInstance()工厂方法,让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其构造...

    单例模式(Singleton Pattern)是一种常用的软件设计模式,是指一个类的实例从始至终只能被创建一次,同时它提供一个静态的getInstance()工厂方法,让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其构造函数设计为私有;在单例类内部定义了一个Singleton类型的静态对象,作为外部共享的唯一实例。

    主要优点:

    1、提供了对唯一实例的受控访问。

    2、由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。

    3、允许可变数目的实例。

    主要缺点:

    1、由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。

    2、单例类的职责过重,在一定程度上违背了“单一职责原则”。

    3、滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。

    适用场景

    在以下情况下可以考虑使用单例模式:

    • (1) 系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器或资源管理器,或者需要考虑资源消耗太大而只允许创建一个对象。

    • (2) 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。

    实现某个类只有一个实例的途径:

    1,让一个全局变量使得一个对象被访问,但是他不能防止外部实例化多个对象。

    2,让类自身保存他的唯一实例,这个类可以保证没有其他实例可以被创建。

    多线程时的单例模式:加锁-双重锁定

    饿汉式单例类:在类被加载时就将自己实例化(静态初始化)。其优点是躲避了多线程访问的安全性问题,缺点是提前占用系统资源。

    懒汉式单例类:在第一次被引用时,才将自己实例化。避免开始时占用系统资源,但是有多线程访问安全性问题。

    方法1:使用__new__方法

    如果想使得某个类从始至终最多只有一个实例,使用__new__方法会很简单。Python中类是通过__new__来创建实例的:

    class Singleton(object):
      def __new__(cls,*args,**kwargs):
        if not hasattr(cls,'_inst'):
          cls._inst=super(Singleton,cls).__new__(cls,*args,**kwargs)
        return cls._inst
    if __name__=='__main__':
      class A(Singleton):
        def __init__(self,s):
          self.s=s   
      a=A('java')  
      b=A('python')
      print id(a),a.s
      print id(b),b.s
    

    结果:

    9621235 python
    9921235 python
    

    通过__new__方法,将类的实例在创建的时候绑定到类属性_inst上。如果cls._inst为None,说明类还未实例化,实例化并将实例绑定到cls.inst,以后每次实例化的时候都返回第一次实例化创建的实例。注意从Singleton派生子类的时候,不要重载__new_。

    方法2:使用装饰器

    我们知道,装饰器(decorator)可以动态地修改一个类或函数的功能。这里,我们也可以使用装饰器来装饰某个类,使其只能生成一个实例,代码如下:

    from functools import wraps
    def singleton(cls):
        instances = {}
        @wraps(cls)
        def getinstance(*args, **kw):
            if cls not in instances:
                instances[cls] = cls(*args, **kw)
            return instances[cls]
        return getinstance
    @singleton
    class MyClass(object):
        a = 1
    

    在上面,我们定义了一个装饰器 singleton,它返回了一个内部函数 getinstance,该函数会判断某个类是否在字典 instances 中,如果不存在,则会将 cls 作为 key,cls(*args, **kw) 作为 value 存到 instances 中,否则,直接返回 instances[cls]。

    方法3:使用元类(metaclass)

    当你编写一个类的时候,某种机制会使用类名字,基类元组,类字典来创建一个类对象。新型类中这种机制默认为type,而且这种机制是可编程的,称为元类__metaclass__ 。

    class Singleton(type):
      def __init__(self,name,bases,class_dict):
        super(Singleton,self).__init__(name,bases,class_dict)
        self._instance=None
      def __call__(self,*args,**kwargs):
        if self._instance is None:
          self._instance=super(Singleton,self).__call__(*args,**kwargs)
        return self._instance
    if __name__=='__main__':
      class A(object):
        __metaclass__=Singleton    
      a=A()
      b=A()
      print id(a),id(b)
    

    结果:

    43645654 43645654
    

    id是相同的。

    例子中我们构造了一个Singleton元类,并使用__call__方法使其能够模拟函数的行为。构造类A时,将其元类设为Singleton,那么创建类对象A时,行为发生如下:

    A=Singleton(name,bases,class_dict),A其实为Singleton类的一个实例。

    创建A的实例时,A()=Singleton(name,bases,class_dict)()=Singleton(name,bases,class_dict).__call__(),这样就将A的所有实例都指向了A的属性_instance上,这种方法与方法1其实是相同的。

    方法4:使用模块

    python中的模块module在程序中只被加载一次,本身就是单例的。可以直接写一个模块,将你需要的方法和属性,写在模块中当做函数和模块作用域的全局变量即可,根本不需要写类。

    而且还有一些综合模块和类的优点的方法:

    class _singleton(object):
      class ConstError(TypeError):
        pass
      def __setattr__(self,name,value):
        if name in self.__dict__:
          raise self.ConstError
        self.__dict__[name]=value
      def __delattr__(self,name):
        if name in self.__dict__:
          raise self.ConstError
        raise NameError
    import sys
    sys.modules[__name__]=_singleton()
    

    python并不会对sys.modules进行检查以确保他们是模块对象,我们利用这一点将模块绑定向一个类对象,而且以后都会绑定向同一个对象了。

    将代码存放在single.py中:

    >>> import single
    >>> single.a=1
    >>> single.a=2
    ConstError
    >>> del single.a
    ConstError
    

    方法5:名字绑定法

    最简单的方法:

    class singleton(object):
      pass
    singleton=singleton()
    

    将名字singleton绑定到实例上,singleton就是它自己类的唯一对象了。

    展开全文
  • 入门学习Linux常用必会60个命令实例详解doc/txt

    千次下载 热门讨论 2011-06-09 00:08:45
    ◆ Windows 95/98常用的FAT 32文件系统:vfat ; ◆ Win NT/2000 的文件系统:ntfs ; ◆ OS/2用的文件系统:hpfs; ◆ Linux用的文件系统:ext2、ext3; ◆ CD-ROM光盘用的文件系统:iso9660。 虽然vfat是...
  • 媒体查询 CSS媒体查询允许开发者基于浏览网站的设备的特性来应用不同的样式申明,最常用的特性是视口宽度。 GCF 谷歌内嵌浏览器框架, 使用此插件,用户可以通过Internet Explorer的用户界面,以Chrome内核的渲染方式...
  • 计算机网络建立的主要目的是实现计算机资源的共享计算机资源主要指计算机( ) A?软件与数据库 B?服务器工作站与软件 C?硬件软件与数据 D?通信子网与资源子网 2?网络中所使用的互连设备?Hub?称为( ) A?集线器 B?路由器...
  • 上下文切换

    2019-10-16 16:21:57
    线程是轻量级进程,可以并行运行并共享该进程的共享地址空间和其他资源 上下文指的是CPU的内容,主要指寄存器和程序计数器在任何时间点的内容。 寄存器是CPU内部少量的非常快的内存(与CPU外部较慢的RAM主内存相对)...

    上下文切换(contextswitch)又称作过程开关任务切换。
    指的是CPU的执行从一个进程或者线程切换到另一个进程或者线程

    线程是轻量级进程,可以并行运行并共享该进程的共享地址空间和其他资源

    上下文指的是CPU的内容,主要指寄存器和程序计数器在任何时间点的内容。

    寄存器是CPU内部少量的非常快的内存(与CPU外部较慢的RAM主内存相对),用于通过快速访问常用值(通常是那些值)来加快计算机程序的执行速度。
    程序计数器是一个专用寄存器,它指示CPU在其指令序列中的位置,并取决于特定的系统,该寄存器保存正在执行的指令的地址或要执行的下一条指令的地址。

    当内核(即操作系统的核心)针对CPU上的进程(包括线程)执行上下文切换:
    (1)暂停一个正在执行的进程并存储进程的CPU状态(即上下文)到内存中,
    (2)从内存中检索下一个进程的上下文,并将其还原到CPU的寄存器中,
    (3)返回到程序计数器指示的位置(返回到中断该过程的代码行)以恢复该过程。

    上下文切换有时被描述为内核在CPU上挂起一个进程的执行并恢复以前已挂起的其他进程的执行。
    尽管此措辞可以帮助阐明概念,但它本身可能会造成混淆,因为根据定义,进程是程序的执行实例。因此,中止进程的措辞可能是更可取的。

    上下文切换只能在内核模式下发生。内核模式是CPU的特权模式,仅内核在其中运行,并提供对所有内存位置和所有其他系统资源的访问。
    其他程序(包括应用程序)最初在用户模式下运行,但是它们可以通过系统调用来运行部分内核代码。系统调用是类活动的进程(即,当前正在CPU中运行的进程)在类Unix操作系统中对内核执行的服务(例如输入/输出(I/O)或进程创建(即创建新流程)。
    I/O可以定义为信息往返于CPU和主内存(即RAM)之间的任何移动,即此组合与计算机用户之间的通信(例如,通过键盘或鼠标),其存储设备(例如磁盘或磁带驱动器)或其他计算机。

    在类Unix操作系统中,这两种模式的存在意味着,当系统调用导致CPU转换为内核模式时,必须进行类似但更简单的操作。这被称为模式切换而不是上下文切换,因为它不会更改当前进程。


    上下文切换是多任务操作系统的基本功能。多任务操作系统是其中多个进程看似同时且在彼此之间互不干扰的单个CPU上执行的操作系统。

    并发的这种幻觉是通过快速连续(每秒数十或数百次)发生的上下文切换来实现的。这些上下文切换是由于进程自愿放弃其在CPU中的时间而导致的,或者是由调度程序在进程用尽其CPU时间片时进行切换而发生的。

    上下文切换也可能由于硬件中断而发生,这是从硬件设备(例如键盘,鼠标,调制解调器或系统时钟)到内核的事件(例如按键,鼠标移动)的信号或来自网络连接的数据到达)。

    Intel80386和更高版本的CPU包含对上下文切换的硬件支持。但是,大多数现代操作系统都执行可以在任何CPU上使用的软件上下文切换,而不是硬件上下文切换,以尝试获得改进的性能。软件上下文切换最早是在Linux中针对具有2.4内核的Intel兼容处理器实现的。

    软件上下文切换所宣称的一个主要优点是,尽管硬件机制可以保存几乎所有的CPU状态,但是软件可以更具选择性,仅保存实际需要保存和重新加载的那部分。但是,对于这在提高上下文切换效率方面到底有多重要,存在一些疑问。它的倡导者还声称,软件上下文切换允许改进切换代码的​​可能性,从而进一步提高效率,并且它允许更好地控制正在加载的数据的有效性。

    上下文切换的成本

    上下文切换通常是计算密集型的。也就是说,这需要相当长的处理器时间,对于每秒数十或数百个开关而言,这可能要在纳秒量级。因此,就CPU时间而言,上下文切换对系统而言是相当大的成本,并且实际上可能是操作系统上最昂贵的操作。

    因此,操作系统设计的主要重点是尽可能避免不必要的上下文切换。然而,这在实践中并不容易实现。实际上,尽管根据消耗的CPU时间的绝对数量来衡量上下文切换的成本一直在下降,但这似乎主要是由于CPU时钟速度的提高,而不是上下文切换本身效率的提高。

    与其他操作系统(包括某些其他类似Unix的系统)相比,Linux的众多优势之一是其上下文切换和模式切换的成本极低。

    展开全文
  • 社会环境威胁方主体可能是个人,也可能是竞争对手组织,具体攻击手段主要有:内部窃密和破坏、非法访问、删改、伪造、重演、抵赖、中断与摧毁等。 (2)技术环境脆弱性 技术环境脆弱性来源于会展信息系统技术...
  • CLH锁 、MCS锁

    2019-11-04 20:22:24
    一.引文 1.1 SMP(Symmetric Multi-Processor): 对称多处理器结构,服务器中多个CPU对称工作,每个CPU访问内存地址所需时间相同。其主要特征是共享,包含对CPU,内存,I/O等进行共享。...常用的PC...
  • 锁机制 CLH锁和MCS锁

    2017-09-11 20:30:01
    1 SMP(Symmetric Multi-Processor)对称多处理器结构,服务器中多个CPU对称工作,每个CPU访问内存地址所需时间相同。其主要特征是共享,包含对CPU,内存,I/O等进行共享。...常用的PC机就属于这种。2 N
  • 特别是对于有分公司的集团性质的公司来说,在总部和分支机构的网络中,存放于总部的文件需要经常访问,但广域网带宽有限,效率低,所以企业管理员可以把常用的文件存储到NAS中,提供高效率访问。另外配合现有的VPN...
  • assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。在实现中,assertion就是在程序中的一条语句,它对一个boolean表达式进行检查,一个正确程序必须保证这个boolean表达式的值为...
  • 第6章 管理Linux操作系统 本章学习目标 熟练使用Shell命令...6.1 用户和组管理 网络服务器有许多用户共享资源 用户管理以账号为对象 账号专属于某个用户全部文件资源及其他数据 6.2 软件包管理 6.3 备份和恢复 6
  • 进程 - 主要指运行在内存中可执行文件。 线程就是进程内部程序流,也就是说操作系统内部支持多进程,而每个进程内部又是支持多线程,线程是轻量,新建线程会共享所在进程系统资源,因此目前主流开发...
  • CPU体系架构与MSC锁

    2020-08-30 17:13:50
    CPU体系架构SMPNUMAMPP自旋锁CLH锁MSC锁 CPU体系架构 SMP SMP(Symmetric Multi-Processor),对称多处理器结构,服务器中多个CPU...可能会导致CPU资源的浪费,常用的PC机就属于这种,其架构简单,但是扩展性很差。 .
  • 进程间通信

    2009-10-12 11:18:00
    什么是进程?进程是一个正在运行的程序的实例,主要由两部分组成:(1)一个操作系统用来管理进程的内核对象。...常用的有4种:消息传递、共享内存、管道、剪贴板:(1)消息传递:不以进程为界限,处理消息的是窗体
  • 网络组建域管理课件1

    2009-02-08 22:27:09
    使用户从对等网的共享资源管理工作中解脱出来 易于管理大量的用户 集中管理,可避免数据分散在不同的计算机中 基于服务器网络的缺点 需要一台配置较高的的计算机作为服务器,增加了网络投资 在服务器上需要安装所需...
  • •存储管理:实质是对存储“空间”管理,主要指对内存管理; •设备管理:实质是对硬件设备管理,其中包括对输入输出设备分配、启动、完成和回收; •进程管理:又称处理机管理,实质上是对处理...
  • 操作系统重点

    2013-01-15 16:59:50
    分时概念:主要若干并发程序对CPU时间的共享。  【了解】  1.操作系统的形成;  2.分时和实时操作系统的特点,见教材16页;  3.操作系统在计算机系统中的地位:是裸机之上的第一层软件,是建立其他所有软件...
  • 共享资源,包括硬件资源、软件资源、数据与信息资源  协同工作,即计算机之间或计算机用户之间协同工作 分类: 计算机网络根据不同角度有不同分类。  按地理区域范围可分为局域网(LAN)、城域网(MAN)...
  • ASP EXCEL导入SQL

    2013-01-23 01:17:24
    静态资源主要应用层中展现层中所要使用到静态资源文件,以及由用户在业务操作中产生文件等,如图片、上传文件等;  而动态数据是用户在使用平台过程中所产生业务数据,在实现业务中,这部分数据大...
  • 网络组建域管理课件2

    2009-02-08 22:29:19
    可以优化服务器的共享资源 减小了网络的通信流量,提高了传输效率。 应用程序在客户机上运行,与服务器无关。 由于应用程序与数据库相隔离,因而数据具有独立性。 大量数据存放在服务器上,节省了客户机存储空间。 ...

空空如也

空空如也

1 2 3 4
收藏数 80
精华内容 32
关键字:

常用的共享资源主要指