关闭

黑马程序员_多线程1

222人阅读 评论(0) 收藏 举报
分类:

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


线程:是程序中的执行线程。

Java 虚拟机允许应用程序并发地运行多个执行线程。


一、线程的创建

创建新执行线程有两种方法。

一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例。

例如,计算大于某一规定值的质数的线程可以写成:

class PrimeThread extends Thread {
	long minPrime;
	PrimeThread(long minPrime) {
		this.minPrime = minPrime;
	}
 
	public void run() {
	// compute primes larger than minPrime
	 . . .
	}
}

然后,下列代码会创建并启动一个线程:

PrimeThread p = new PrimeThread(143);
p.start();

创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后可以分配该类的实例,在创建Thread 时作为一个参数来传递并启动。

采用这种风格的同一个例子如下所示: 

class PrimeRun implements Runnable {
	long minPrime;
	PrimeRun(long minPrime) {
		this.minPrime = minPrime;
	}
 
	public void run() {
	// compute primes larger than minPrime
	 . . .
	}
}

然后,下列代码会创建并启动一个线程:

PrimeRun p = new PrimeRun(143);
new Thread(p).start();


那么,线程的创建方式选择哪个更好呢?

答案是实现Runnable接口更好一些


1.因为实现Runnable接口可以避免Java单继承的局限性。

当一个类继承了Thread,就不可以在继承其他类了。

而当一个类实现了Runnable,它一样可以继承其他类。

比如 class Demo extends SuperDemo implements Runnable{}


2.更符合面向对象的设计。

run()方法的作用是用来封装线程要运行的代码。

那么run()方法所属的对象,就是线程任务对象。

Thread类的子类对象即使线程对象,又是线程任务对象。耦合性很强。

有了Runnable接口,可以将线程任务和线程进行解耦,提高了程序的扩展性。


所以建议使用Runnable接口的方式完成线程的创建。


二、多线程的安全问题

多线程安全问题:当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,另一个线程参与进来执行,就会导致共享数据的错误。

解决办法:对多条操作共享数据的语句,只能让一个线程执行。在执行过程中,其他线程不可以参与执行。

Java提供了一种解决方式:同步代码块 synthronized(Object obj) { 需要被被同步的代码 }

Object 如同锁,持有锁的线程可以在同步代码块中执行。没有持有锁的线程即使持有CPU的执行权,也无法执行同步代码。

同步的前提:

1.必须要有两个或以上的线程

2.必须是多个线程使用同一个锁

好处:解决了多线程的安全问题。 弊端:线程需要判断锁,较为消耗资源。

如何找安全问题?

1.明确哪些代码是多线程运行代码

2.明确共享数据

3.明确多线程运行代码中哪些语句是操作共享数据的

第二种同步的方式:同步函数  用synchronized修饰函数

在非静态同步函数中,用的锁是this。因为函数需要被对象调用,那么函数都有一个所属对象引用,这个引用就是this。

在静态同步函数中,用的锁是类名.class。静态函数进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象:类名.class,该对象的类型是Class类。


另外,在单例设计模式中有饿汉式和懒汉式,实际开发用饿汉式,但面试常考懒汉式。 

懒汉式特点:实例的延迟加载
问题:多线程访问时会出现安全问题。
用同步代码块或同步函数均可,但有些低效,用双重判断解决效率问题,同步代码块使用的锁为该类所属的字节码文件对象。

class Single {
	private static Single s = null;
	private Single(){}
	public static Single getInstance() {
		if(s == null) {
			synchronized(Single.class) {
				if(s == null)
					s = new Single();
			}
		}
		return s;						
	}
}



三、死锁

通常死锁的出现是因为:同步中嵌套同步,锁却不同。 

开发中要避免写出死锁程序。

下面是一个出现死锁的程序:

class DeadLock implements Runnable {
	private boolean flag;
	DeadLock(boolean flag) {
		this.flag = flag;
	}
	public void run() {
		for (int i = 0; i < 40; i++) {	
			if(flag) {
				synchronized(Lock.lock1) {
					System.out.println("iflock1..."+i);
					synchronized(Lock.lock2) {
						System.out.println("iflock2..."+i);
					}
				}
			}
			else {
				synchronized(Lock.lock2) {
					System.out.println("elselock2..."+i);
					synchronized(Lock.lock1) {
						System.out.println("elselock1..."+i);
					}
				}
			}
		}
	}
}

class Lock {
	public static Object lock1 = new Object(); 
	public static Object lock2 = new Object(); 
}


0
0

猜你在找
【直播】机器学习&数据挖掘7周实训--韦玮
【套餐】系统集成项目管理工程师顺利通关--徐朋
【直播】3小时掌握Docker最佳实战-徐西宁
【套餐】机器学习系列套餐(算法+实战)--唐宇迪
【直播】计算机视觉原理及实战--屈教授
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之矩阵--黄博士
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之凸优化--马博士
【套餐】Javascript 设计模式实战--曾亮
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:2002次
    • 积分:113
    • 等级:
    • 排名:千里之外
    • 原创:10篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章存档