------- android培训、java培训、期待与您交流! ----------
要知道什么叫做线程,首先要知道进程是怎么回事:正在进行中的程序。其实进程就是一个应用程序运行时的内存分配空间
线程:其实就是进程中一个程序执行控制单元,一条执行路径。进程负责的是应用程序的空间的标示;线程负责的是应用程序的执行顺序
一个进程中可以多执行路径,称之为多线程
一个进程至少有一个线程在运行,当一个进程中出现多个线程时,就称这个应用程序是多线程应用程序,每个线程在栈区中都有自己的执行空间,自己的方法区、自己的变量
JVM启动时就启动了多个线程,至少有两个线程会执行:
1:执行main函数的线程
该线程的任务代码都定义在main函数中
2:负责垃圾回收的线程
创建线程方式一:继承Thread类
步骤:
1:定义一个类继承Thread类
2:覆盖Thread类中的run方法,复写run方法
3:直接创建Thread的子类对象创建线程
4:调用start方法开启线程并调用线程的任务run方法执行
线程的四种状态:
创建线程方式二:实现Runnable接口
步骤:
3:Thread类对象调用start方法开启线程
实现Runnable接口的好处:
1:将线程的任务从线程的子类中分离出来,进行了单独的封装按照面向对象的思想将任务的封装成对象
2:避免了java单继承的局限性(如果一个类已经有了自己的父类,就不可以继承Thread类,java就提供了一个接口Runnable)
线程的安全问题:
由线程的随机性及多个线程访问出现延迟导致
同步的引入:将操作共享数据的语句在某一时段让一个线程执行完,在执行过程中,其他线程不能进来执行
同步代码块格式:
synchronized(对象)
{
需要同步的代码;
}
同步定义的前提:
1:必须要有两个或者两个以上的线程,才需要同步
2:多个线程必须保证使用的是同一个锁
同步函数:其实就是将同步关键字定义在函数上,让函数具备了同步性,在函数上加上synchronized修饰符即可。同步函数所使用的锁就是this锁
在一个类中只有一个同步,可以使用同步函数。如果有多同步,必须使用同步代码块,来确定不同的锁。所以同步代码块相对灵活一些
同步死锁:通常只要将同步进行嵌套,就可以看到现象。同步函数中有同步代码块,同步代码块中还有同步函数
典型案例卖票:
class Ticket implements Runnable//extends Thread
{
private int num = 100;
Object obj = new Object();
public void run()
{
while(true)
{
synchronized(obj)
{
if(num>0)
{
System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--);
}
}
}
}
}
class TicketDemo
{
public static void main(String[] args)
{
Ticket t = new Ticket();//创建一个任务对象;
Thread t1 = new Thread(t);//创建了一个线程;
Thread t2 = new Thread(t);//创建了一个线程;
Thread t3 = new Thread(t);//创建了一个线程;
Thread t4 = new Thread(t);//创建了一个线程;
t1.start();
t2.start();
t3.start();
t4.start();
}
线程间通信
概念:多个线程在操作同一个资源,但是操作的动作却不一样
等待唤醒涉及的方法:
wait():将同步中的线程处于冻结状态。释放了执行权,释放了资格。同时将线程对象存储到线程池中
notify():唤醒线程池中某一个等待线程
notifyAll():唤醒的是线程池中的所有线程
使用上述方法注意事项:
1:这些方法存在与同步中
2:使用这些方法时必须要标识所属的同步锁
3:锁可以是任意对象,所以任意对象调用的方法一定定义Object类中
为什么操作线程的方法定义在Object类中?
由于这三个方法都需要定义同步内,并标示所属的同步锁,既然被锁调用,而锁又可以是任意对象,那么能被任意对象调用的方法一定定义在Object类中
wait和sleep区别:
wait:可以指定时间也可以不指定时间;不指定时间,只能由对应的notify或者notifyAll来唤醒
sleep:必须指定时间,时间到自动从冻结状态转成运行状态(临时阻塞状态)
wait:线程会释放执行权,而且线程会释放锁
sleep:线程会释放执行权,但不是不释放锁
线程的停止也即run方法的结束,有两种方法:
2:使用interrupt(中断)方法,该方法是结束线程的冻结状态,使线程回到运行状态中来
---------< java.lang.Thread>----------
方法摘要 | |
---|---|
static int | activeCount() 返回当前线程的线程组中活动线程的数目。 |
void | checkAccess() 判定当前运行的线程是否有权修改该线程。 |
static Thread | currentThread() 返回对当前正在执行的线程对象的引用。 |
static void | dumpStack() 将当前线程的堆栈跟踪打印至标准错误流。 |
static int | enumerate(Thread[] tarray) 将当前线程的线程组及其子组中的每一个活动线程复制到指定的数组中。 |
static Map<Thread,StackTraceElement[]> | getAllStackTraces() 返回所有活动线程的堆栈跟踪的一个映射。 |
ClassLoader | getContextClassLoader() 返回该线程的上下文 ClassLoader。 |
static Thread.UncaughtExceptionHandler | getDefaultUncaughtExceptionHandler() 返回线程由于未捕获到异常而突然终止时调用的默认处理程序。 |
long | getId() 返回该线程的标识符。 |
String | getName() 返回该线程的名称。 |
int | getPriority() 返回线程的优先级。 |
StackTraceElement[] | getStackTrace() 返回一个表示该线程堆栈转储的堆栈跟踪元素数组。 |
Thread.State | getState() 返回该线程的状态。 |
ThreadGroup | getThreadGroup() 返回该线程所属的线程组。 |
Thread.UncaughtExceptionHandler | getUncaughtExceptionHandler() 返回该线程由于未捕获到异常而突然终止时调用的处理程序。 |
static boolean | holdsLock(Object obj) 当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。 |
void | interrupt() 中断线程。 |
static boolean | interrupted() 测试当前线程是否已经中断。 |
boolean | isAlive() 测试线程是否处于活动状态。 |
boolean | isDaemon() 测试该线程是否为守护线程。 |
boolean | isInterrupted() 测试线程是否已经中断。 |
void | join() 等待该线程终止。 |
void | join(long millis) 等待该线程终止的时间最长为 millis 毫秒。 |
void | join(long millis, int nanos) 等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。 |
void | run() 如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的run 方法;否则,该方法不执行任何操作并返回。 |
void | setContextClassLoader(ClassLoader cl) 设置该线程的上下文 ClassLoader。 |
void | setDaemon(boolean on) 将该线程标记为守护线程或用户线程。 |
static void | setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh) 设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序。 |
void | setName(String name) 改变线程名称,使之与参数 name 相同。 |
void | setPriority(int newPriority) 更改线程的优先级。 |
void | setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh) 设置该线程由于未捕获到异常而突然终止时调用的处理程序。 |
static void | sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。 |
static void | sleep(long millis, int nanos) 在指定的毫秒数加指定的纳秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。 |
void | start() 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。 |
String | toString() 返回该线程的字符串表示形式,包括线程名称、优先级和线程组。 |
static void | yield() 暂停当前正在执行的线程对象,并执行其他线程。 |
jdk1.5以后将同步和锁封装成对象 ,并将操作锁的隐式方式定义到了该对象中, 将隐式动作变成了显示动作。
Lock接口: 出现替代了同步代码块或者同步函数,将同步的隐式锁操作变成现实锁操作,同时更为灵活。可以一个锁上加上多组监视器。
lock():获取锁。
unlock():释放锁,通常需要定义finally代码块中。
Condition接口:出现替代了Object中的wait notify notifyAll方法
将这些监视器方法单独进行了封装,变成Condition监视器对象可以任意锁进行组合。