多线程
线程的特点:
1.进程是资源分配的最小单位,线程是最小的执行单位。
2.一个进程可以有多个线程。
3.线程共享进程资源。
实现线程的两种形式:
1.继承Thread类(java.lang.Thread)
常用构造方法:
public Thread() 分配一个新的Thread对象。 此构造具有相同的效
果Thread (null, null, gname)
public Thread(String name) 分配一个新的Thread对象。 此构造具有相同的效果Thread (null, null, name) 。
public Thread(Runnable target)
public Thread(Runnable target,String name)
常用方法:
1.public void run() 线程运行时执行的方法
2.public void start() 导致此线程开始执行; Java虚拟机调用此线程的run方法,注:如果start方法调用一个已经启动的线程,系统将抛出IllegalThreadStateException异常。
3.public static void sleep(long millis) throws InterruptedException 使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。
4.public final void join() throws InterruptedException 等待这个线程死亡。
5.public final void join(long millis) throws InterruptedException 等待这个线程死亡的时间最多为millis毫秒。 0的超时意味着永远等待。
6.public final void join(long millis,int nanos) throws InterruptedException 等待最多millis毫秒加上这个线程死亡的nanos纳秒。
7.public void interrupt() 中断这个线程。注意:调用此方法结束线程时,会抛出InterruptedException异常,在项目中通常在处理异常方法中关闭数据库连接等操作。
8. public static void yield()给当前正处于运行状态的线程一个提醒,告知她可以将资源礼让给其他线程,但这仅是一种暗示,没有任何机制能保证当前线程会将资源礼让,对于多任务操作系统来说,不需要调用此方法。
9. public final void setPriority(int newPriority) 更改此线程的优先级。优先级1~10依次递增,静态常量:MAX_PRIORITY (10),MIN_PRIORITY(1) ,NORM_PRIORITY (5,默认情况)。
注意:如果多个线程处于同一优先级,谁先来谁先执行,但这种执行顺序时理论上的,具体CPU是怎样执行的无法预测,即优先级高的应该先执行,而不是肯定先执行,该方法效果并不明显,每个新产生的线程都继承了父线程的优先级。
10.public final boolean isAlive() 测试这个线程是否活着。 如果一个线程已经启动并且尚未死亡,那么线程是活着的。
注意:
- 当执行一个线程程序时,就自动产生一个线程,主方法正是在这个线程上运行的,当不在启动其他线程时,该程序就为单线程程序。
- 主方法线程启动由Java虚拟机负责, 程序员负责启动自己的线程。
- 通常在润run()方法中使用无限循环的形式,使得线程一直运行下去,所以要指定一个跳出循环的条件。
- 在主方法没有调用start方法之前,Thread对象只是一个实例,而不是一个真正的线程。
- 线程的执行顺序和执行时间不是由代码来控制的,而是由CPU来控制的。
2.实现Runnable接口
实质上,Thread类实现了Runnable接口,其中的run()方法是对Runnable接口中的run()方法的具体实现。
public Thread(Runnable target)
public Thread(Runnable target,String name)
使用Runnable接口启动新的线程的步骤如下:
- 建立Runnable对象
- 使用参数为Runnable对象的构造方法创建Thread实例
- 调用start()方法启动线程。
如:
public class A implements Runnable{
public void run(){
}
public static void main(String[] args){
A a = new A();
Thread thread = new Thread(a);
thread.strart();
}
}
注:Thread类的start()方法产生一个新的线程,该线程运行Thread子类的run()方法。
线程在运行状态下发出输入/输出请求,该线程将进入阻塞状态,在其等待输入/输出结束时线,程进入就绪状态,即使系统资源空闲,线程依然不能回到运行状态。
线程的生命周期:
出生状态、就绪状态、运行状态、等待状态、休眠状态、阻塞状态、死亡状态
使线程进入就绪状态有以下方法:
1.sleep()
2.wait()
3.等待输入/输出完成
当线程处于就绪状态后,以下方法可以使线程再次进入运行状态
1.notify()
2.notifyAll()
3.interrupt()
4.线程的休眠时间结束
5.输入输出结束。
线程同步(synchronized)
使用多线程程序,就会发生两个线程抢占资源的问题。实质上线程安全问题来源于两个线程同时存取单一对象的数据
使用方法:
1.同步代码块
synchronized(Object){
}
Object为任意一个对象,每个对象都存在一个标志位,并具有两个值,分别为1,0.一个线程运行到同步代码块时首先检查该对象的标志位,如果为0状态,表明此同步块中存在其他线程在运行。这是该线程处于就绪状态,直到处于同步代码块中的线程执行完同步代码块中的代码为止。这时该对象标志位为1,该线程才能执行同步代码块中的代码,并将Object对象的标志设置为0,防止其他线程执行同步块中的代码。
public class ThreadSafeTest implements Runnable {
int num = 10;
public void run() {
while (true) {
synchronized ("") {
if (num > 0) {
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("tickets" + --num);
}
}
}
}
public static void main(String[] args) {
ThreadSafeTest t = new ThreadSafeTest();
Thread tA = new Thread(t);
Thread tB = new Thread(t);
Thread tC = new Thread(t);
Thread tD = new Thread(t);
tA.start();
tB.start();
tC.start();
tD.start();
}
}
2.同步方法
synchronized void f(){
}
注意:必须将每个能访问共享资源的方法修饰为synchronized,否则会出错。