黑马程序员_学习笔记多线程

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流!-------

一、定义

进程:正在运行中的程序。

线程:就是进程中一个执行单元或执行情景或执行路径。负责进程中代码执行的控制单元。

多线程:一个进程中至少要有一个线程,当一个进程中有多个线程时,就是多线程。

多线程的好处:可以让多部分代码同时执行。

      同时执行不同于同步执行。

创建多线程的目的:

       当有多部分代码需要同时执行时。而且每一个线程都有自己要执行的内容,这个内容称之为:线程任务。

       简单说:启动多线程就是为了执行任务,当任务有多个,需要同时执行时,就需要多个线程。

如何创建线程?

       Java要调用底层才能完成进程的建立和线程的创建,所以java对外提供了描述线程的对象,方便程序员对线程的操作。

Thread类:描述线程的类。

创建线程有两种方式:

创建线程的第一种方式:继承Thread类,覆盖run方法。

              自定义线程要运行的内容放在run方法中。

             run方法中可以调用其他方法。

       步骤:

              1、定义类继承Thread类。

              2、覆盖Thread类招工难的run方法。

              3、创建Thread类的子类对象创建线程对象。

              4、调用线程的start方法,开启线程。

              star()方法做了两件事:1、开启线程。2、调用run方法。

public class ThreadDemo {

    public static void main(String[] args) {
       Demo2 d1 = new Demo2("线程1");
       Demo2 d2 = new Demo2("线程2");

//     d1.start(); //开启线程并执行run方法。
//     d2.start();
       d1.run();
       d2.run();
    }
}

class Demo extends Thread {
    private String name;
    Demo(String name){
       this.name = name;
    }
    //线程任务。
    @Override
    public void run(){
       for(int x=1;x<=10;x++){
           for(int y=0;y<100;y++){}
           System.out.println(name+"------"+x+":::::::"+getName());//返回当前线程的名字。
           System.out.println(name+"------"+x+":::::::"+currentThread().getName());//返回当前正在执行线程的名称。
       }
    }
}    

  Thread类中的方法:

             static Thread currentThread()返回对当前正在执行线程对象的引用。

              void start()开启线程,并调用run方法。

              Sleep(long millis):在指定的毫秒内让当前中在执行线程休眠。

注意:

       1、多个线程的运行是不规律的。

       2、必须得所有线程程序运行结束,进程才结束。

3、调用run方法和调用start方法的区别:

              调用run方法,仅仅是一般对象调用对象中的方法,并没有开启线程。

              调用start方法,开启一个线程,让这个线程去执行run方法中的内容。   

线程的状态:

       1、被创建。

       2、运行:这种状态的线程,具备着cpu的执行资格,具备着执行资格。

       3、冻结:这种状态的线程,释放了cpu执行资格,并释放了cpu执行权。相当于睡着了,但还会醒来。

                    有两种方法实现:

                            1sleep(time).唤醒sleep(time时间到)

                            2wait()睡着,唤醒notify()   wait()方法也可以指定时间,如果不指定时间需要用notify()来唤醒。(是Object中的方法。)

       4、临时阻塞状态:这种状态的线程,具备着cpu执行权,不具备执行资格。

       5、消亡:线程结束了。通过stop()方法来完成。

创建线程的第二种方式:

1、定义一个类实现Runnable接口。
        2、覆盖Runnable接口中的run方法。            将线程要运行的代码存储到run方法中。
        3、创建该接口的子类对象。
       4、通过Thread类进行线程的创建,并将Runnable接口的子类对象作为Thread的构造函数的实参进行传递。
       因为要明确运行要运行那个run方法。
       5、调用Thread类中的start方法开启线程。
实现Runnable接口的好处:
       1、通过Runnable接口可以降低线程对象和线程任务之间的耦合性。
             如果使用继承Thread类的方式,Thread类即封装了线程任务,又是线程对象。
       2、该方式避免了单继承的局限性。
              所以创建线程建议使用实现Runnable接口的方式。
同步:
              同步原理:其实就是将需要同步的代码进行封装,并在该代码上加一个锁。
              同步好处:解决了多线程安全问题。
              同步弊端:降低性能。
              (注意):加了同步,安全问题还在,如何解决?利用同步的两个前提来解决。
              同步的前提:
                    必须要保证在同步中有多个线程,因为同步中只有一个线程,该同步是没有意义的。
                    必须要保证多个线程在同步中使用的是同一个锁。
注意:当锁定义在局部中时,相当于每个线程都具备一个锁。这时就不是同一个锁了。
多线程安全问题:
多线程安全的原因:
1、  多个线程在操作共享数据。
2、  操作共享数据的代码有多条。    
一个线程在执行多条操作共享数据的过程中,其他线程参与了运算,这时就会发生安全问题。

分析多线程是否安全的依据:
线程中任务中有没有共享数据,该数据是否被多条语句操作。

安全问题解决方案:只要保证一个线程在执行多条操作共享数据的语句时,其他线程不能参与运算即可。当该线程都执行完后,其他线程才可以执行这些语句。在多线程操作的代码上加上同步(synchronzied)。

Synchornzied同步原理:其实就是将需要同步的代码进行封装,并在该代码上加上一个锁。
同步的好处:解决多线程安全问题。
同步弊端:降低程序的运行效率,同时有可能会出现死锁情况。

同步函数和同步代码块有什么区别?
1、  同步函数使用的锁是this,同步代码块使用的锁是任意指定的对象。
建议开始时,使用同步代码块,因为锁可以是任意的。尤其是需要用到多个不同锁时。

静态同步函数使用的锁是什么?
       静态随着类的加载而加载,这时内存中只存储的对象至少一个,就是该类字节码文件对象(类名.class)。所以静态同步函数使用的锁是字节码对象。

public class ThisLockDemo {

	public static void main(String[] args) {
		/*
		 * 
		 * 通过两个线程来验证同步函数使用的锁是什么?
		 */
		Ticket3 t = new Ticket3();

		Thread t1 = new Thread(t);
		Thread t2 = new Thread(t);

		t1.start();
		try {
			Thread.sleep(10);
		} catch (Exception e) {
		} // 停顿,以免main线程一下执行完。
		t.setFlag();
		t2.start();
	}
}

class Ticket3 implements Runnable {

	private int num = 200;

	// private Object obj = new Object();

	private boolean flag = true;

	public void run() {
		if (flag)
			while (true) {
				synchronized (this) {// 使用obj锁和this锁的区别?
					if (num > 0) {
						try {
							Thread.sleep(10);
						} catch (Exception e) {
						}
						System.out.println(Thread.currentThread().getName()
								+ "......code....." + num--);
					}
				}
			}
		else
			while (true) {
				show();
			}
	}

	// 将标记改为false。
	public void setFlag() {
		flag = false;
	}
	public synchronized void show() {// this

		if (num > 0) {
			System.out.println(Thread.currentThread().getName()
					+ ".......func...." + num--);
		}
	}
}

死锁:

最常见的死锁情况:同步嵌套。

同步中还有同步,两个同步用的不是同一个锁。


线程间通信:多个线程在处理同一资源,但是处理的动作却不同。



------Java培训、Android培训、iOS培训、.Net培训、期待与您交流!-------


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值