黑马程序员_java基础学习笔记10_多线程

-------  android培训 java培训 、期待与您交流! ----------



一.线程的概念
1.线程
线程是程序执行的一条路径, 一个进程中可以包含多条线程
多线程并发执行可以提高程序的效率, 可以同时完成多项工作
2.多线程的应用场景
迅雷开启多条线程一起下载
QQ同时和多个人一起视频
服务器同时处理多个客户端请求
二.开启新线程
1.继承Thread
定义类继承Thread
重写run方法
把新线程要做的事写在run方法中
创建线程对象
开启新线程, 内部会自动执行run方法
2.实现Runnable
定义类实现Runnable接口
实现run方法
把新线程要做的事写在run方法中
创建自定义的Runnable对象
创建Thread对象, 传入Runnable
调用start()开启新线程, 内部会自动调用Runnable的run()方法
3.两种方式的区别
区别一:
a.由于子类重写了Thread类的run(), 当调用start()时, 直接找子类的run()方法
b.构造函数中传入了Runnable的引用, 成员变量记住了它, start()调用run()方法时内部判断成员变量Runnable是否为空, 不为空则执行Runnable的run()
区别二:
a.继承Thread只能是单继承,如果自己定义的线程类已经有了父类,就不能再继承了
b.实现Runnable接口可以多实现,即使自己定义线程类已经有父类可以实现Runnable接口
总结:继承Thread的好处是:可以直接使用Thread类中的方法,代码简单
 弊端是:如果已经有了父类,就不能用这种方法
       实现Runnable接口的好处是:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口,而且接口是可以多实现的
         弊端是:不能直接使用Thread中的方法需要先获取到线程对象后,才能得到Thread的方法,代码复杂
4.线程的优先级
   JVM会对所有的线程,进行默认的级别
分成三个级别
最低 -- 1
默认 -- 5
  最高 -- 10
   线程的优先级越高,莫一时刻获得CPU的时间片的机会就越多
   获取优先级 int getPriority() 
三.Thread类常用方法
1.设置名字
通过构造函数可以传入String类型的名字
通过setName(String)方法可以设置线程对象的名字
2.获取名字
通过getName()方法获取线程对象的名字
3.获取当前线程对象
Thread.currentThread(), 主线程也可以获取
4.休眠
Thread.sleep(毫秒,纳秒), 控制当前线程休眠若干毫秒1秒= 1000毫秒 1秒 = 1000 * 1000* 1000纳秒 1000000000
public class ThreadDemo3 {
	public static void main(String[] args)throws Exception {
		/*for(int x = 0 ; x < 20 ;x++){
			//线程休眠
			Thread.sleep(100);
			System.out.println("main.."+x);
		}*/
		new SleepThread().start();
	}
}
5.守护
setDaemon(), 设置一个线程为守护线程, 该线程不会单独执行, 当其他非守护线程都执行结束后, 自动退出
public static void main(String[] args) throws Exception{
		//创建线程对象,变成后台线程
		DaemonThread t0 = new DaemonThread();
		//setDaemon 必须在start开始前设置
		t0.setDaemon(true);
		t0.start();
	}
6.加入
join(), 当前线程暂停, 等待指定的线程执行结束后, 当前线程再继续
join(int), 可以等待指定的毫秒之后继续
public class ThreadDemo4 {
	public static void main(String[] args) throws Exception{
		//创建JoinThread线程对象
		JoinThread j0 = new JoinThread();
		JoinThread j1 = new JoinThread();	
		j0.start();
		j0.join();
		j1.start();
		for(int x = 0 ; x < 100; x++)
			System.out.println(Thread.currentThread().getName()+" "+x);
	}
}
7.让步
Thread类的静态方法 yield() 指方法写在哪个线程中,哪个线程就会让出自己的CPU资源
public static void main(String[] args) {
		//创建2个线程对象
		YieldThread t0 = new YieldThread();
		YieldThread t1 = new YieldThread();
		t0.start();
		t1.start();
	}
四.线程之间的同步
1.哪些情况下需要同步
当多线程并发, 有多段代码同时执行,或者多线程共享同一数据时,我们希望某一段代码执行的过程中CPU不要切换到其他线程工作. 这时就需要同步.
如果两段代码是同步的, 那么同一时间只能执行一段, 在一段代码没执行结束之前, 不会执行另外一段代码.
2.同步代码块
使用synchronized关键字加上一个锁对象来定义一段代码, 这就叫同步代码块
多个同步代码块如果使用相同的锁对象, 那么他们就是同步的
3.同步方法
使用synchronized关键字修饰一个方法, 该方法中所有的代码都是同步的
非静态同步方法默认使用当前对象this作为锁对象
静态方法同步默认的锁对象是,所在类的字节码对象
4.线程安全问题
多线程并发操作同一数据时, 就有可能出现线程安全问题
使用同步技术可以解决这种问题, 把操作数据的代码进行同步, 不要多个线程一起操作
5.死锁问题
多线程同步的时候, 如果同步代码嵌套, 使用相同锁, 就有可能出现死锁
尽量不要嵌套使用
五.线程的生命周期

六.线程之间的通信 
       针对同一资源的操作有不同种类的线程,需要线程之间的通信.可以通过设置线程和获取线程针对同一个    对象进行操作.如果希望线程等待,可以调用wait()方法;如果希望唤醒等待的线程,可以调用notify()方法;    以上两个方法必须在同步代码中执行,并且使用同步锁对象来调用.
   注意:notify()方法是随机唤醒一个线程
notifyAll()方法是唤醒所有线程
JDK5之前无法唤醒指定的一个线程
如果多个线程之间通信,需要使用notifyAll()通知所有线程,用while来反复判断条件.
    JDK5之后的线程控制: 1.同步时,可以使用ReentrantLock类的lock()和unlock()方法进行同步
    2.通信时,使用ReentrantLock类的newCondition()方法可以获取Conditioon对       象.需要等待的时候使用Condition的await()方法,唤醒的时候用signal()方       法.不同的线程使用不同的Condition,这样就能区分唤醒的时候找哪个线程.
   下面来代码解释下单例设计模式的懒汉式和饿汉式
public class Demo4_Single {
	 /*单例设计模式
<span style="white-space:pre">	</span>  *保证类在内存中只有一个对象
<span style="white-space:pre">	</span>  */
	public static void main(String[] args) {
		/*Single s1 = Single.s;
		Single.s = null;
		Single s2 = Single.s;
		System.out.println(s1 == s2);*/
		/*Single s1 = Single.getInstance();
		Single s2 = Single.getInstance();
		System.out.println(s1 == s2);*/
		Single s1 = Single.s;
		Single s2 = Single.s;
		System.out.println(s1 == s2);
	}
}
//饿汉式
/*class Single {
	//第一步,私有构造函数
	private Single(){}
	//第二步,创建本类对象
	private static Single s = new Single();
	//第三步,定义公有的访问方法将对象返回
	public static Single getInstance() {
		return s;
	}
}*/
//懒汉式
/*class Single {
	//第一步,私有构造函数
	private Single(){}
	//第二步,声明一个本类的引用
	private static Single s;
	//第三步,定义公有的访问方法将对象返回
	public static Single getInstance() {
		if(s == null)
			//线程1停,线程2停
			s = new Single();
		return s;
	}
}*/
/*
 * 饿汉式和懒汉式的区别
 * 1,饿汉式时间换空间,懒汉式空间换时间
 * 2,饿汉式在多线程访问没问问题,只创建一个对象
 *   懒汉式又名单例的延迟加载形式,在多线程访问的时候,有可能会出现多个实例
 * 
 */
class Single {
	//第一步,私有构造函数
	private Single(){}
	//第二步,创建本类对象
	public final static Single s = new Single();
}
八.线程组,线程池,匿名内部类方式使用多线程以及Runtime类和使用
   1.线程组
Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进      行控制.在默认情况下,所有的线程都属于主线程组.声明方法为:public final getThreadGroup() 还可以      给线程设置分组.方法为:Thread(ThreadGroup group,Runnable target,String name)
   2.线程池
程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好       的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。
线程池里的每一个线程代码结束后,并不会死亡,而是再次会带线程池中称为空闲状态,等待下一个对象来  使用,在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池.有如下几个方 法: public static ExecutorService newCachedThreadPool()
public static ExecutorService newFixedThreadPool(int nThreads)
public static ExecutorService newSingleThreadExecutor()
这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象 代表的线程,它提供了以下的方法: Future<?> submit(Runnable task)
<T> Future<T> submit(Callable<T> task)
       3.匿名内部类方法使用多线程,方法主要有:
new Thread(){ 代码......}   start();
new Thread(new Runnable() {代码......}) start();
       4.Runtime类
每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。可以通过                getRuntime 方法获取当前运行时。 应用程序不能创建自己的 Runtime 类实例。使用方法为:
  public Prosess exec(String command)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值