黑马程序员:java基础知识(多线程)

---------------------- ASP.Net+Unity开发 .Net培训、期待与您交流! ----------------------

java基础——多线程

1、进程和线程:
    所谓进程,就是正在执行的程序。每个进程执行都有一个顺序,该顺序称为一个执行路径或称为一个控制单元。线程就是进程中的一个独立的控制单元,线程在控制着进程的执行。一个进程中至少有一个线程。
    java虚拟机启动时,会有一个进程“java.exe”。该进程中至少有一个线程负责java程序执行,而且这个线程的运行代码存在于main函数中,该线程被称为主线程。值得注意的是,java虚拟机启动时,不止一个线程,严格来说,应该至少有两个线程,一个是主线程,一个是垃圾回收机制的线程。

2、线程的创建方式:
  (1)继承Thread类,覆盖run方法,调用线程的start方法启动线程。start方法的作用是,启动该线程并调用run方法。
    创建方式:NewThread extends Thread
             new NewThread().start();
  (2)实现Runnable接口,实现接口中的run方法,通过Thread类,建立线程对象,将Runnable的子类对象作为一个实际参数传递给Thread的构造方法,调用Thread类的start方法,开启线程,并执行Runnable子类的run方法。这样做的原因是,run方法所属的对象是Runnable的子类对象,创建的线程要去执行这个run方法,那么,就必须明确该run方法所属的对象。
    创建方式:NewRunnable implements Runnable
              new Thread(new NewRunnable()).start();
  (3)这两种创建方式的区别:实现接口的方式,线程的执行代码存放在接口子类的run方法中;继承Thread的方式,线程的执行代码存放在Thread子类的run方法中。实现接口的方式,避免了单继承的局限性。建议使用实现接口的方式创建线程。

3、run和start的区别:
    run方法:在Thread类中就定义了一个功能,就是run方法。这个方法用于存储线程要运行的代码。
    new Thread().start():创建线程,启动线程,调用线程的run方法
    new Thread().run():创建线程,使用Thread对象调用run方法,只是普通的对象调用方法,线程并未启动。

4、多线程的运行机制
    多线程在运行时,我们往往认为是多个线程在同时运行,其实不然。因为单核CPU在某一时刻,只能执行一个线程。多个线程都在获取CPU的执行权,CPU执行到谁,谁就运行。CPU在做着高速的切换,以达到同时运行的假象。我们可以形象的把多线程的运行,看作是在互相抢夺CPU的执行权。我们在执行多线程时,发现每一次的结果都有可能不一样,这就是多线程的一个特性——随机性。哪个线程“抢到”了CPU的执行权,那个就执行,至于执行多久,CPU说了算。

5、线程的状态:
  (1)被创建:new Thread() 或 new Thread(Runnable)
  (2)运行:在被创建状态调用start方法,达到运行状态;
  (3)冻结:冻结状态又分为睡眠和等待两种状态。在运行状态执行sleep(时间)方法,会使线程进入睡眠状态,没有执行资格,直到睡眠时间到,这是可能会进入阻塞状态,或进入运行状态,由CPU决定。另外一种,在运行状态执行wait()方法时,会是进程进入等待状态,没有执行资格,直到执行了notify()方法将其唤醒,进入阻塞或运行状态。
  (4)阻塞:阻塞状态是介于运行状态和冻结状态的一个临时状态;
  (5)消亡:run()方法执行结束,或执行了stop()方法。

  图解:

进程状态


6、获取和设置线程对象的名称:
    每个线程都有自己默认的名称“Thread-编号”,编号从0开始。在Thread类中,有getName()这个方法,用于获取线程的名称。setName(Name)用于自定义线程的名称。另一种自定义线程名称的方式是,使用Thread的构造方法Thread(String name).
        ①Thread t = new Thread("t1")
        ②Thread t = new Thread(Runnable,"t1")
    Thread.currentThread():获取当前线程对象,所以通常情况下会使用,Thread.cunrrentThread().getName()这种方式来获取当前线程的名称。

7、线程安全
    有一个共享数据,有多条语句在操作它,当一个线程运行时,没有全部执行完这些操作语句时,它的执行权就被另一个线程获取,这种情况,就会导致共享数据出现错误。就出现了线程安全问题。如何解决这个问题呢?通过思考我们知道,针对共享数据,每一次只能由一个线程来操作。就是一个线程全部操作完后,其他线程才可以操作。这就是使线程同步。
    java中,针对线程安全问题提供了专业的处理——线程同步。关键字:synchronized(对象锁),括号中的对象锁的作用就是,避免多个线程同时进入执行。
    它的原理:就像门上的一把锁,当某个人获得钥匙后,进入房间,从里面反锁,别人即使得到了钥匙,也进不了门;直到里面的人出来,别人才能进去。
    这个关键字可以作为一个修饰符,修饰方法,被修饰的方法,就是一个线程同步的方法。如果修饰的是一个非静态的方法,那么它的锁就是该类的对象;如果修饰的是一个静态方法,那么它的锁就是该方法所在类的字节码文件对象(类名.class)。这个关键字也可以修饰代码块,被修饰的就是同步代码块。格式与修饰方法不同,必须指定锁。如下:
       修饰方法:
           public synchronized void show(){} //锁是该类的对象(this)
            public static synchronized void show(){} //锁是(类名.class)
       修饰代码块:
           synchronized(对象锁){ 同步代码块 }
    同步的前提:①有两个或两个以上的线程;②多个线程必须使用同一个锁。
    同步线程的好处,就是解决的线程安全问题。但也有弊端,多个线程在执行时,需要判断锁,较耗资源。
    如何判断哪些代码该同步,哪些代码不该同步?
        ①明确哪些代码是多线程运行的代码;
        ②明确共享数据;
        ③明确多线程运行代码中,哪些语句是操作共享数据的。
    通过对多线程的了解,我们发现“懒汉式”单例模式,存在线程安全问题,在多线程中使用时,需要处理一下:
        public static Single getInstance()
        {
            if(s==null)//之所以多加这一层,是减少多线程对锁的判断。
            {
                synchronized(Single.class)
                {
                    if(s==null)
                        s = new Single();
                }
            }
        }
        通过上面的处理后,就解决了线程安全问题。

    在做线程同步处理的时候,有可能会出现死锁。一个共享资源,被多种方式操作,如一个方法或代码块,如果同步的锁是不一样的,当两个线程访问该资源时,就有可能会出现死锁。死锁的例子:

	public void run(){
		if(flag){
			synchronized(MyLock.locka){    //同步的锁是MyLock.locka
				System.out.println("if locka");
				synchronized(MyLock.lockb){  //同步的锁是MyLock.lockb
					System.out.println("if lockb");
				}
			}
		}else{
			synchronized(MyLock.lockb){    //同步的锁是MyLock.lockb
				System.out.println("else lockb");
				synchronized(MyLock.locka){   //同步的锁是MyLock.locka
					System.out.println("else locka");
				}
			}
		}
	}
               在上面这个例子中,两种访问情况使用了不同的锁,一个拿了一个锁。就相当于两个人一人拿了一支筷子,谁都吃不上饭。但即使是上面这种情况,也会出现和谐的情况,正常输出。

    在开发过程中,我们应当避免死锁发生,也就是尽量避免使用同步嵌套。对同一个资源的同步操作,一定要使用相同的锁。


---------------------- ASP.Net+Unity开发 .Net培训、期待与您交流! ----------------------

详细请查看:http://edu.csdn.net


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值