一、Java中实现多线程的两种方式
1) 继承Thread类
Thread类包含了包含和创建线程所需的一切东西。Thread 最重要的方法是 run(),编写线程程序时需要覆盖 run() 方法,run() 方法是与别的线程并行运行的,故存在资源竞争和同步问题。。Thread 还包含一个特殊的方法 start(),其作用是对线程进行特殊的初始化,然后调用run()。
调用start方法方可启动线程,而run方法只是thread的一个普通方法调用,还是在主线程里执行。应该把需要并行处理的代码放在run()方法中,start()方法启动线程将自动调用 run()方法,这是由jvm的内存机制规定的。并且run()方法必须是public访问权限,返回值类型为void.。
2) 实现Runable接口
Runable接口只有一个函数 run(),该函数必须由实现了该接口的类来实现。使用 Runable 接口的时候不能直接创建所需类的对象并运行它,而必须从 Thread 类的一个实例内部运行。
二、线程状态
线程生命周期中共有4中状态:新状态、可执行状态、死亡状态和阻塞状态。其中,
新状态:线程已创建,而start()还没有调用;
可执行状态:线程可以执行,等待CPU时间被分配给该线程后即可;
死亡状态:run()返回后线程就会死亡。或者调用stop()或者destroy()方法也会使得线程死亡,然而stop()会产生异常,destroy()则是强制终止从而没有释放锁;
阻塞状态:线程不会被分配CPU时间,无法执行。
阻塞状态情况比较复杂,线程 进入阻塞状态的原因主要是:
1)调用sleep(ms),进入睡眠
2)调用suspend(),挂起线程。(调用resume()恢复运行)
3)调用wait(),暂停线程。(调用notify()或者notifyAll()恢复运行)
4)I/O 阻塞
5)调用另一个处于锁定状态的对象的同步方法
三、对象的锁
Java中所有对象都具有隐式关联的监视程序,即“锁”。程序不用去生成一个锁的对象,因为任何对象都具有了锁,通常在程序中都使用this对象。
与锁有关的方法有:
1)wait()
调用该方法的线程需要等待,直到得到该对象的锁,线程才能继续执行。
2)wait(long)和wait(long,int)
传递的参数指定了线程能够等到的最长时间,如果指定时间内没有得到锁,则会抛出异常interrupedException,程序处理完异常后继续运行。
3)notify()和notifyAll()
在锁对象上调用notify()或者notifyAll()方法就能够释放对象上的锁。其中,notify()只能唤醒一个等待该锁的线程;而notifyAll()则会唤醒所有等待该锁的线程,然而被唤醒的线程中哪个会获得锁是由虚拟机来决定的。
四、线程的同步
synchronized 语句通过使用对象锁同步多个线程对某一特定代码段的访问,在任何时候都只能有一个线程来执行被保护的代码。
1) 继承Thread类
Thread类包含了包含和创建线程所需的一切东西。Thread 最重要的方法是 run(),编写线程程序时需要覆盖 run() 方法,run() 方法是与别的线程并行运行的,故存在资源竞争和同步问题。。Thread 还包含一个特殊的方法 start(),其作用是对线程进行特殊的初始化,然后调用run()。
调用start方法方可启动线程,而run方法只是thread的一个普通方法调用,还是在主线程里执行。应该把需要并行处理的代码放在run()方法中,start()方法启动线程将自动调用 run()方法,这是由jvm的内存机制规定的。并且run()方法必须是public访问权限,返回值类型为void.。
2) 实现Runable接口
Runable接口只有一个函数 run(),该函数必须由实现了该接口的类来实现。使用 Runable 接口的时候不能直接创建所需类的对象并运行它,而必须从 Thread 类的一个实例内部运行。
二、线程状态
线程生命周期中共有4中状态:新状态、可执行状态、死亡状态和阻塞状态。其中,
新状态:线程已创建,而start()还没有调用;
可执行状态:线程可以执行,等待CPU时间被分配给该线程后即可;
死亡状态:run()返回后线程就会死亡。或者调用stop()或者destroy()方法也会使得线程死亡,然而stop()会产生异常,destroy()则是强制终止从而没有释放锁;
阻塞状态:线程不会被分配CPU时间,无法执行。
阻塞状态情况比较复杂,线程 进入阻塞状态的原因主要是:
1)调用sleep(ms),进入睡眠
2)调用suspend(),挂起线程。(调用resume()恢复运行)
3)调用wait(),暂停线程。(调用notify()或者notifyAll()恢复运行)
4)I/O 阻塞
5)调用另一个处于锁定状态的对象的同步方法
三、对象的锁
Java中所有对象都具有隐式关联的监视程序,即“锁”。程序不用去生成一个锁的对象,因为任何对象都具有了锁,通常在程序中都使用this对象。
与锁有关的方法有:
1)wait()
调用该方法的线程需要等待,直到得到该对象的锁,线程才能继续执行。
2)wait(long)和wait(long,int)
传递的参数指定了线程能够等到的最长时间,如果指定时间内没有得到锁,则会抛出异常interrupedException,程序处理完异常后继续运行。
3)notify()和notifyAll()
在锁对象上调用notify()或者notifyAll()方法就能够释放对象上的锁。其中,notify()只能唤醒一个等待该锁的线程;而notifyAll()则会唤醒所有等待该锁的线程,然而被唤醒的线程中哪个会获得锁是由虚拟机来决定的。
四、线程的同步
synchronized 语句通过使用对象锁同步多个线程对某一特定代码段的访问,在任何时候都只能有一个线程来执行被保护的代码。
synchronized (taskQueue) {
newTask.setTaskId(++taskCounter);
newTask.setSubmitTime(new Date());
taskQueue.add(newTask);
/* 唤醒队列, 开始执行 */
taskQueue.notifyAll();
}
以上例子中,执行 synchronized (taskQueue) ,线程必须取得对象taskQueue的锁。如果线程没有获取到对象taskQueue的锁,线程就会停止在 synchronized 指令上。直到线程离开 synchronized 指令保护的代码段,线程会将锁返回给对象taskQueue。